web-dev-qa-db-fra.com

Obtenir des résultats entre deux dates dans PostgreSQL

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".

27
Psyche
 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.

48
Marco Mariani

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 intervalle start <= 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.

Performance

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:

29
Erwin Brandstetter

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'
17
Chris

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');
1
vyegorov

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?

0
Edmund
SELECT *
FROM ecs_table
WHERE (start_date, end_date) OVERLAPS ('2012-01-01'::DATE, '2012-04-12'::DATE + interval '1');
0
user9251288

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

0
rxpande