Expandir consulta para além da especificada na cláusula WHERE
-
22-07-2019 - |
Pergunta
Deve haver uma maneira melhor de escrever essa consulta.
Eu quero selecionar todos os dados entre um par de datas. Idealmente as primeiras e últimas linhas do conjunto de resultados seriam aqueles especificada na cláusula WHERE. Se não existirem essas linhas, eu quero que as linhas anteriores e posteriores à gama solicitado.
Um exemplo:
Se meus dados é:
...
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
...
E a consulta é:
SELECT *
FROM data_bahf
WHERE param_id = 135321
AND datetime >= '20090311 10:30:00'
AND datetime <= '20090311 12:00:00'
Eu quero que os dados retornados para incluir a linha às 10:15, e que de 0:30. Não apenas aqueles que estritamente cumprir a cláusula WHERE.
Este é o melhor que eu vim acima com.
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
(Ignorar o uso de SELECT * por agora)
EDIT: Tenho índices em param_id, data e hora, e (param_id, data e hora)
Solução
Em primeiro lugar, certifique-se que você tem um composta ??strong> índice em (param_id, datetime)
Em segundo lugar, consulta como esta:
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')
Apenas verificado, ele é executado em 1.215 ms
para uma tabela de exemplo de linhas 200,000
Outras dicas
Eu diria o seguinte:
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'
)
EDIT: Fallback acrescentou
.
Quando não há nenhuma linha correspondente ao sub-consulta, que irá resultar em um valor NULL
, que deve ser travado por ISNULL()
ou o operador BETWEEN
irá falhar e a consulta principal irá retornar nenhuma linha em tudo.