Développer la requête au-delà de celle spécifiée dans la clause WHERE
-
22-07-2019 - |
Question
Il doit exister un meilleur moyen d'écrire cette requête.
Je veux sélectionner toutes les données entre deux dates. Idéalement, les première et dernière lignes du jeu de résultats seraient celles spécifiées dans la clause WHERE. Si ces lignes n'existent pas, je veux les lignes précédant et suivant la plage demandée.
Un exemple:
Si mes données sont:
...
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
...
Et la requête est:
SELECT *
FROM data_bahf
WHERE param_id = 135321
AND datetime >= '20090311 10:30:00'
AND datetime <= '20090311 12:00:00'
Je souhaite que les données renvoyées incluent la ligne à 10h15 et celle de 12h30. Pas seulement ceux qui respectent strictement la clause WHERE.
C’est le meilleur que j’ai trouvé.
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
(Ignorez l'utilisation de SELECT * pour l'instant)
EDIT: J'ai des index sur param_id, datetime et (param_id, datetime)
La solution
Tout d'abord, assurez-vous de disposer d'un index composite sur (id_param, date / heure)
Deuxièmement, utilisez la requête suivante:
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')
Vient de cocher, il est exécuté dans 1.215 ms
pour un exemple de tableau de 200 000
lignes
Autres conseils
Je dirais ceci:
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 ajouté.
Lorsqu'il n'y a pas de ligne correspondant à la sous-requête, il en résulte une valeur NULL
, qui doit être interceptée par ISNULL ()
ou le BETWEEN
L'opérateur échouera et la requête principale ne renverra aucune ligne.