2012-07-09 34 views
43

Me gustaría obtener la lista de días entre las dos fechas (incluyéndolos) en una base de datos PostgreSQL . Por ejemplo, si tuviera:Obteniendo la lista de fechas en un rango en PostgreSQL

  • fecha de inicio: 29 Junio ​​2012
  • fecha de finalización: 3 Julio 2012

continuación, el resultado debería ser:

29 june 2012 
30 june 2012 
1 july 2012 
2 july 2012 
3 july 2012 

lo que sería la mejor manera de hacer esto en PostgreSQL?

Gracias.

Respuesta

59
select CURRENT_DATE + i 
from generate_series(date '2012-06-29'- CURRENT_DATE, 
    date '2012-07-03' - CURRENT_DATE) i 

o incluso más corto:

select i::date from generate_series('2012-06-29', 
    '2012-07-03', '1 day'::interval) i 
6

Esto debe hacerlo:

select date '2012-06-29' + i 
from generate_series(1, (select date '2012-07-3' - date '2012-06-29')) i 

Si no desea repetir la fecha_inicial en las cosas subselect ser un poco más complicado:

with min_max (start_date, end_date) as (
    values (date '2012-06-29', date '2012-07-3') 
), date_range as (
    select end_date - start_date as duration 
    from min_max 
) 
select start_date + i 
from min_max 
    cross join generate_series(1, (select duration from date_range)) i; 

(véase la respuesta de Maniek para una gran parte mejor versión del problema "sin repetición")

+0

gracias, les han intentado y casi funciona. Ambos tienen todas las fechas, pero el primer día (el 29 de junio). Funciona si cambia el "1" en la función generated_series de "0" – Javi

+0

generate_series es una nueva para mí. –

+2

más simple, sin necesidad de repetir: 'select CURRENT_DATE + i de generate_series (fecha '2012-06-29'- CURRENT_DATE, fecha '2012-07-03' - CURRENT_DATE) I' – maniek

0

Si ya tiene una base de datos que desea consultar:

SELECT 
    TO_CHAR(date_column,'DD Mon YYYY') 
FROM 
    some_table 
WHERE 
    date_column BETWEEN '29 Jun 2012' AND '3 JUL 2012' 

GROUP BY date_column 
ORDER BY date_column 

Esto dará como resultado:

"29 Jun 2012" 
"30 Jun 2012" 
"01 Jul 2012" 
"02 Jul 2012" 
"03 Jul 2012" 
+0

hecho sin no tengo fechas en cualquier mesa. Es solo una lista de las fechas que necesito mostrar en un informe y tal vez no haya ningún dato en algunos días. – Javi

0

Esta función/SQL PLPG que hacer el truco:

CREATE OR REPLACE FUNCTION getDateList(date1 date, date2 date) 
RETURNS SETOF date AS 
$BODY$ 
DECLARE 
    count integer; 
    lower_limit integer := 0; 
    upper_limit integer := date2 - date1; 
BEGIN 
    FOR count IN lower_limit..upper_limit LOOP 
     RETURN NEXT date1 + count; 
    END LOOP; 
    RETURN; 
END; 
$BODY$ 
LANGUAGE plpgsql VOLATILE 
0

Si el intervalo de fechas debe provenir de una expresión de tabla, puede utilizar el siguiente constructor :

DROP TABLE tbl ; 
CREATE TABLE tbl (zdate date NOT NULL); 
INSERT INTO tbl(zdate) VALUES('2012-07-01') , ('2012-07-09'); 

WITH mima AS (
     SELECT MIN(zdate)::timestamp as mi 
     , MAX(zdate)::timestamp as ma 
     FROM tbl 
     ) 
SELECT generate_series(mima.mi, mima.ma, '1 day':: interval):: date 
FROM mima 
     ; 

Las conversiones son necesarias porque generate_series() no toma argumentos de fecha.

4

Por cosas como esta su general, es útil tener una tabla de fechas en el sistema.

Al igual que una tabla de números, pueden ser muy útiles y más rápidos de usar que generar las fechas sobre la marcha, especialmente cuando amplía a grandes conjuntos de datos.

Dicha tabla de fechas de 1900 a 2100 será muy pequeña, por lo que no hay mucho más de almacenamiento.

Editar: No sé por qué esto va a ser rechazado, probablemente será el mejor para el rendimiento. Además tiene muchas otras ventajas. ¿Desea vincular las órdenes a los números de rendimiento de un trimestre? Es un simple enlace entre las tablas. (Order.OrderDate -> Dates.Date -> Dates.Quarter -> PerformanceTotal.Quarter) etc. Es lo mismo para trabajar días hábiles, como el último día hábil de un mes o el primer martes del mes anterior. Como una tabla de números, ¡los recomiendo encarecidamente!

+1

¿Esa serie también tiene cosas como el trimestre, el año, el mes, etc.? Muy útil si está generando informes en tales períodos de tiempo. – BJury

+0

Sí, para secuencias desiguales como esa, las tablas de calendario probablemente serían más bonitas que 'generate_series'; Probablemente debería haber dicho "normalmente * no hay necesidad de tablas de calendario". –

26

Como timestamp:

select generate_series('2012-06-29', '2012-07-03', '1 day'::interval); 

    generate_series  
------------------------ 
2012-06-29 00:00:00-03 
2012-06-30 00:00:00-03 
2012-07-01 00:00:00-03 
2012-07-02 00:00:00-03 
2012-07-03 00:00:00-03 

o fundido a date:

select (generate_series('2012-06-29', '2012-07-03', '1 day'::interval))::date; 

generate_series 
----------------- 
2012-06-29 
2012-06-30 
2012-07-01 
2012-07-02 
2012-07-03 
3
select generate_series('2012-06-29', '2012-07-03', '1 day'::interval)::date; 
+1

Explique su solución para que todos podamos aprender de ella. – Hannes

+1

¿En qué se diferencia esto de la respuesta de Clodoaldo? –

Cuestiones relacionadas