Espandere la query oltre quella specificata nella clausola WHERE
-
22-07-2019 - |
Domanda
Deve esserci un modo migliore per scrivere questa query.
Voglio selezionare tutti i dati tra una coppia di date. Idealmente, la prima e l'ultima riga del set di risultati sarebbero quelle specificate nella clausola WHERE. Se quelle righe non esistono, voglio che le righe precedano e seguano l'intervallo richiesto.
Un esempio:
Se i miei dati sono:
...
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 la query è:
SELECT *
FROM data_bahf
WHERE param_id = 135321
AND datetime >= '20090311 10:30:00'
AND datetime <= '20090311 12:00:00'
Voglio che i dati restituiti includano la riga alle 10:15 e quella delle 12:30. Non solo quelli che soddisfano rigorosamente la clausola WHERE.
Questo è il migliore che ho ideato.
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
(Ignora l'uso di SELECT * per ora)
EDIT: Ho indici su param_id, datetime e (param_id, datetime)
Soluzione
Innanzitutto, assicurati di avere un indice composito su (param_id, datetime)
In secondo luogo, interroga in questo modo:
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')
Appena controllato, viene eseguito in 1.215 ms
per una tabella di esempio di 200.000
righe
Altri suggerimenti
Direi questo:
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 aggiunto.
Quando non è presente alcuna riga corrispondente alla sottoquery, verrà generato un valore NULL
, che deve essere rilevato da ISNULL ()
o TRA
l'operatore avrà esito negativo e la query principale non restituirà alcuna riga.