Расширить запрос за пределы указанного в предложении WHERE.
-
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
оператор завершится неудачно, и основной запрос вообще не вернет строк.