Расширить запрос за пределы указанного в предложении WHERE.

StackOverflow https://stackoverflow.com/questions/643885

  •  22-07-2019
  •  | 
  •  

Вопрос

Должен быть лучший способ написать этот запрос.

Я хочу выбрать все данные между парой дат.В идеале первая и последняя строки результирующего набора должны быть теми, которые указаны в предложении WHERE.Если эти строки не существуют, я хочу, чтобы строки предшествовали запрошенному диапазону и следовали за ним.

Пример:

Если мои данные:

...
135321, 20090311 10:15:00
135321, 20090311 10:45:00
135321, 20090311 11:00:00
135321, 20090311 11:15:00
135321, 20090311 11:30:00
135321, 20090311 12:30:00
...

И запрос:

    SELECT * 
    FROM data_bahf 
    WHERE param_id = 135321 
    AND datetime >= '20090311 10:30:00' 
    AND datetime <= '20090311 12:00:00'

Я хочу, чтобы возвращаемые данные включали строку в 10:15 и в 12:30.Не только те, которые строго соответствуют пункту WHERE.

Это лучшее, что я придумал.

SELECT * FROM (
    SELECT * 
    FROM data_bahf 
    WHERE param_id = 135321 
    AND datetime > '20090311 10:30:00' 
    AND datetime < '20090311 12:00:00'

    UNION

    (
        SELECT * FROM data_bahf 
        WHERE param_id = 135321 
        AND datetime <= '20090311 10:30:00' 
        ORDER BY datetime desc
        LIMIT 1
    )

    UNION

    (
        SELECT * FROM data_bahf 
        WHERE param_id = 135321 
        AND datetime >= '20090311 12:00:00'
        ORDER BY datetime asc
        LIMIT 1
    )
) 
AS A
ORDER BY datetime

(Пока игнорируйте использование SELECT *)

РЕДАКТИРОВАТЬ:У меня есть индексы по param_id, datetime и (param_id, datetime)

Это было полезно?

Решение

Во-первых, убедитесь, что у вас есть композитный индекс на (param_id, datetime)

Во-вторых, такой запрос:

SELECT  *
FROM    data_bahf
WHERE   param_id = 135321
        AND datetime BETWEEN
        COALESCE(
        (
        SELECT  MAX(datetime)
        FROM    data_bahf
        WHERE   param_id = 135321
              AND datetime <= '2009-01-01 00:00:00'
        ), '0001-01-01')
        AND 
        COALESCE(
        (
        SELECT  MIN(datetime)
        FROM    data_bahf
        WHERE   param_id = 135321
              AND datetime >= '2009-01-02 00:00:00'
        ), '9999-01-01')

Только что проверил, запускается 1.215 ms за образец таблицы 200,000 ряды

Другие советы

Я бы сказал это:

SELECT 
  o.* 
FROM 
  data_bahf o
WHERE 
  o.param_id = 135321 
  AND o.datetime BETWEEN
  ISNULL(
    (
      SELECT   MAX(datetime) 
      FROM     data_bahf i
      WHERE    i.param_id = 135321 AND i.datetime <= '20090311 10:30:00'
    ),
    '0001-01-01 00:00:00'
  )
  AND
  ISNULL(
    (
      SELECT   MIN(datetime) 
      FROM     data_bahf i
      WHERE    i.param_id = 135321 AND i.datetime >= '20090311 12:00:00'
    ),
    '9999-12-31 23:59:59'
  )

РЕДАКТИРОВАТЬ:Добавлен резервный вариант.
Если нет строки, соответствующей подзапросу, это приведет к NULL значение, которое должно быть уловлено ISNULL() или BETWEEN оператор завершится неудачно, и основной запрос вообще не вернет строк.

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top