Expande la consulta más allá de la especificada en la cláusula WHERE
-
22-07-2019 - |
Pregunta
Debe haber una mejor manera de escribir esta consulta.
Quiero seleccionar todos los datos entre un par de fechas. Idealmente, la primera y la última fila del conjunto de resultados serían las especificadas en la cláusula WHERE. Si esas filas no existen, quiero que las filas precedan y sigan el rango solicitado.
Un ejemplo:
Si mis datos son:
...
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
...
Y la consulta es:
SELECT *
FROM data_bahf
WHERE param_id = 135321
AND datetime >= '20090311 10:30:00'
AND datetime <= '20090311 12:00:00'
Quiero que los datos devueltos incluyan la fila a las 10:15 y la de las 12:30. No solo aquellos que cumplen estrictamente con la cláusula WHERE.
Esto es lo mejor que se me ocurrió.
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
(Ignore el uso de SELECT * por ahora)
EDITAR: Tengo índices en param_id, datetime y (param_id, datetime)
Solución
Primero, asegúrese de tener un índice compuesto en (param_id, datetime)
Segundo, 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')
Recién verificado, se ejecuta en 1.215 ms
para una tabla de muestra de 200,000
filas
Otros consejos
Yo diría esto:
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'
)
EDITAR: Fallback agregado.
Cuando no hay una fila que coincida con la subconsulta, dará como resultado un valor NULL
, que debe ser capturado por ISNULL ()
o el ENTRE
el operador fallará y la consulta principal no devolverá ninguna fila.