que - Obteniendo lista de fechas en un rango en PostgreSQL
sql fecha mayor que otra (8)
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 enviado a la 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
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:
- fecha de inicio: 29 de junio de 2012
- fecha de finalización: 3 de julio de 2012
entonces el resultado debería ser:
29 june 2012
30 june 2012
1 july 2012
2 july 2012
3 july 2012
¿Cuál sería la mejor manera de hacer esto en PostgreSQL?
Gracias.
Esta función PLpg / SQL haría 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
Esto debería hacerlo:
select date ''2012-06-29'' + i
from generate_series(1, (select date ''2012-07-3'' - date ''2012-06-29'')) i
Si no quiere repetir la fecha_inicio en la subselección, las cosas se complican un poco:
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;
(Ver la respuesta de maniek para una versión mucho mejor del problema de "no repetir")
Para cosas como esta es generalmente ú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 se 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 sea 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!
Si el rango de fechas proviene de una expresión de tabla, puede usar la siguiente construcción:
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
;
Los moldes son necesarios porque generate_series () no toma argumentos de fecha.
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"
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
select generate_series(''2012-06-29'', ''2012-07-03'', ''1 day''::interval)::date;