Getting date list in a range in PostgreSQL

后端 未结 8 434
悲&欢浪女
悲&欢浪女 2020-11-28 07:59

I\'d like to get the list of days between the two dates (including them) in a PostgreSQL database. For example, if I had:

  • start date: 29 june
相关标签:
8条回答
  • 2020-11-28 08:17

    For things like this its generally handy to have a dates table in the system.

    Just like a numbers table they can be very useful and quicker to use than generating the dates on the fly, especially when you scale up to large data sets.

    Such a date table from 1900 to 2100 will be very small, so there isn't much over head in storage.

    Edit: Dunno why this is getting voted down, it will probably be the best for performance. Plus it has so many other advantages. Want to link orders to a an quarters performance numbers? Its a simple link between the tables. (Order.OrderDate -> Dates.Date -> Dates.Quarter -> PerformanceTotal.Quarter) etc. Its the same for dealing with working days, like the last working day of a month, or the first Tuesday of the previous month. Like a numbers table, I'd strongly recommend them!

    0 讨论(0)
  • 2020-11-28 08:20

    If the date range should come from a table expression, you could use the following construct:

    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
            ;
    

    The casts are needed because generate_series() does not take date arguments.

    0 讨论(0)
  • 2020-11-28 08:31
    select CURRENT_DATE + i 
    from generate_series(date '2012-06-29'- CURRENT_DATE, 
         date '2012-07-03' - CURRENT_DATE ) i
    

    or even shorter:

    select i::date from generate_series('2012-06-29', 
      '2012-07-03', '1 day'::interval) i
    
    0 讨论(0)
  • 2020-11-28 08:33

    This should do it:

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

    If you don't want to repeat the start_date in the subselect things get a bit more complicated:

    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;
    

    (See maniek's answer for a much better version of the "no-repeat" problem)

    0 讨论(0)
  • 2020-11-28 08:34

    As 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
    

    or casted to 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
    
    0 讨论(0)
  • 2020-11-28 08:37

    This PLpg/SQL function would do the trick:

    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 讨论(0)
提交回复
热议问题