Tengo un requisito

START_DATE : 03/01/2018
END_DATE : 28/12/2018

Necesito una consulta que enumere todos los meses fecha de inicio y fecha de finalización entre estas dos fechas como esta

StartMonth   EndMonth
03/01/2018  31/01/2018
01/02/2018  28/01/2018
01/03/2018  31/03/2018
01/04/2018  30/04/2018
01/05/2018  31/05/2018
01/06/2018  30/06/2018
01/07/2018  31/07/2018
01/08/2018  31/08/2018
01/09/2018  30/09/2018
01/10/2018  31/10/2018
01/11/2018  30/11/2018
01/12/2018  28/12/2018

También necesito una consulta que enumere todas las fechas de inicio y finalización del trimestre entre estas dos fechas como esta

StartQuarter EndQuarter
03/01/2018   31/03/2018
01/04/2018   30/06/2018
01/07/2018   30/09/2018
01/10/2018   28/12/2018
0
R Khan 22 ene. 2018 a las 23:18

3 respuestas

La mejor respuesta

Estos deberían funcionar.

Por meses:

    select greatest(:start_date, trunc(add_months( :start_date, level - 1), 'MON')) as startmonth,
           least(:end_date, last_day(add_months( :start_date, level - 1))) as endmonth
      from dual
connect by level <= trunc(months_between(trunc( :end_date, 'MON'), trunc( :start_date, 'MON'))) + 1;

Para cuartos:

    select greatest(:start_date, trunc(add_months( :start_date, 3 * (level - 1)), 'Q')) as startmonth,
           least(:end_date, last_day(add_months( :start_date, 3 * (level - 1) + 2))) as endmonth
      from dual
connect by level <= trunc(months_between(trunc( :end_date, 'Q'), trunc( :start_date, 'Q'))) / 3 + 1;

Donde: fecha_inicio y: fecha_final son sus fechas de inicio y finalización.

1
GriffeyDog 22 ene. 2018 a las 21:01

Aquí está la variante que no se limita a ninguna longitud de rango específica:

SELECT TO_CHAR(GREATEST(
         LAST_DAY(ADD_MONTHS(:start_date, LEVEL - 2)) + 1,
         :start_date
       ), 'dd/mm/yyyy') AS StartMonth,
       TO_CHAR(LEAST(
         :end_date, 
         LAST_DAY(ADD_MONTHS(:start_date, LEVEL - 1))
       ), 'dd/mm/yyyy') AS EndMonth
FROM dual
CONNECT BY LAST_DAY(ADD_MONTHS(:start_date, LEVEL - 1)) <= LAST_DAY(:end_date);

EDITAR: después de corregir el rango de fechas de inicio, se parece mucho a la respuesta aceptada, con una forma diferente de hacer aritmética de fechas. Y trimestralmente, el uso de {GriffeyDog de TRUNC es probablemente la mejor apuesta aún.

0
Alex Savitsky 22 ene. 2018 a las 23:55

Aquí hay un CTE (expresión de tabla común) que genera las entradas mensuales:

WITH
    aset
    AS
        (SELECT DATE '2018-01-03' start_month, DATE '2018-12-28' last_month
           FROM DUAL),
    bset (start_month, end_month, last_month)
    AS
        (SELECT start_month, LEAST (ADD_MONTHS (TRUNC (start_month, 'MM'), 1) - 1, last_month) end_month, last_month
           FROM aset
         UNION ALL
         SELECT ADD_MONTHS (TRUNC (start_month, 'MM'), 1)
              , LEAST (ADD_MONTHS (start_month, 2) - 1, last_month)
              , last_month
           FROM bset
          WHERE end_month < last_month)
SELECT start_month, end_month
  FROM bset;


START_MONTH END_MONTH
----------- ---------
03-JAN-18   31-JAN-18
01-FEB-18   02-MAR-18
01-MAR-18   31-MAR-18
01-APR-18   30-APR-18
01-MAY-18   31-MAY-18
01-JUN-18   30-JUN-18
01-JUL-18   31-JUL-18
01-AUG-18   31-AUG-18
01-SEP-18   30-SEP-18
01-OCT-18   31-OCT-18
01-NOV-18   30-NOV-18
01-DEC-18   28-DEC-18
0
Brian Leach 22 ene. 2018 a las 22:14
48389602