J'ai le tableau suivant:
+-----------+-----------+------------+----------+
| id | user_id | start_date | end_date |
| (integer) | (integer) | (date) | (date) |
+-----------+-----------+------------+----------+
Les champs start_date
et end_date
contiennent des valeurs de date telles que YYYY-MM-DD
.
Une entrée de cette table peut ressembler à ceci: (1, 120, 2012-04-09, 2012-04-13)
.
Je dois écrire une requête capable d'extraire tous les résultats correspondant à une certaine période.
Le problème est que si je veux récupérer les résultats de 2012-01-01
à 2012-04-12
, j'obtiens 0 résultats même s'il existe une entrée avec start_date = "2012-04-09"
et end_date = "2012-04-13"
.
SELECT *
FROM mytable
WHERE (start_date, end_date) OVERLAPS ('2012-01-01'::DATE, '2012-04-12'::DATE);
Fonctions datetime est la section appropriée de la documentation.
En supposant que vous souhaitiez toutes les "chevauchements", c’est-à-dire toutes celles qui ont au moins un jour en commun.
Essayez d’envisager des périodes de temps sur une ligne de temps droite et de les déplacer sous vos yeux pour vous permettre de voir conditions nécessaires.
SELECT *
FROM tbl
WHERE start_date <= '2012-04-12'::date
AND end_date >= '2012-01-01'::date;
Ceci est parfois plus rapide pour moi que OVERLAPS
- ce qui est un autre bon moyen de le faire (comme @Marco a déjà fourni ).
Notez la subtile différence ( par documentation ):
OVERLAPS
prend automatiquement la valeur antérieure de la paire en tant que début. Chaque période est considérée comme représentant le demi-ouvert intervallestart <= time < end
, sauf si début et fin sont égaux en ce que cas, il représente cet instant unique. Cela signifie par exemple que deux périodes avec seulement un point final en commun ne se chevauchent pas.
Gras accent mien.
Pour les grandes tables, le droit index peut améliorer les performances (beaucoup).
CREATE INDEX tbl_date_inverse_idx ON tbl(start_date, end_date DESC);
Peut-être avec une autre colonne d'index (principale) si vous avez d'autres conditions sélectives.
Notez l'ordre inverse des deux colonnes. Explication détaillée:
vient d'avoir la même question et a répondu de cette façon, si cela pouvait aider.
select *
from table
where start_date between '2012-01-01' and '2012-04-13'
or end_date between '2012-01-01' and '2012-04-13'
Pour qu'une requête fonctionne dans les paramètres régionaux, considérez en formatant la date vous-même:
SELECT *
FROM testbed
WHERE start_date >= to_date('2012-01-01','YYYY-MM-DD')
AND end_date <= to_date('2012-04-13','YYYY-MM-DD');
En regardant les dates pour lesquelles cela ne fonctionne pas - celles où le jour est inférieur ou égal à 12 - je me demande si les dates sont analysées au format AAAA-JJ-MM?
SELECT *
FROM ecs_table
WHERE (start_date, end_date) OVERLAPS ('2012-01-01'::DATE, '2012-04-12'::DATE + interval '1');
Aucune infraction mais pour vérifier les performances de SQL j'ai exécuté une partie de la solution susmentionnée pgsql.
Permettez-moi de vous partager les statistiques des 3 meilleures solutions possibles.
1) Pris: 1,58 MS Moy.
2) Pris: 2,87 MS en moyenne
3) Pris: 3,95 MS en moyenne
Maintenant, essayez ceci:
SELECT * FROM table WHERE DATE_TRUNC('day', date ) >= Start Date AND DATE_TRUNC('day', date ) <= End Date
Maintenant, cette solution a pris: 1,61 Moy.
Et la meilleure solution est la première proposée par marco-mariani