使用当前日期

时间:2017-02-05 06:39:59

标签: sql postgresql

我有一个子请求,返回此信息:

item_id, item_datetime,        item_duration_in_days
1,       '7-dec-2016-12:00',    3                     
2,       '8-dec-2016-11:00',    4                    
3,       '20-dec-2016-05:00',   10                    
4,       '2-jan-2017-14:00',    50                    
5,       '29-jan-2017-22:00',   89

我想让“item_id”落入“now()”。为此,算法是:

  1) var duration_days = interval 'item_duration_in_days[i]'

  2) for the very first item: 
        new_datetime[i] = item_datetime[i] + duration_days

  3) for others: 
     - if a new_datetime from the previous step overlaps with the current item_datetime[i]:
        new_datetime[i] = new_datetime[i - 1] + duration_days

    - else:
        new_datetime[i] = item_datetime[i] + duration_days


  4) return an item for each iteration:
     {id, item_datetime, new_datetime}

也就是说,会有类似的东西:

item_id  item_datetime    new_datetime
1         7 dec 2016       10 dec 2016
2        11 dec 2016       15 dec 2016
3        20 dec 2016       30 dec 2016
4         2 jan 2017       22 feb 2017   <------- found because now() == Feb 5
5        22 feb 2017       21 may 2017

我该怎么做?我认为它应该像“折叠”功能。可以通过sql请求完成吗?或者必须是中间变量存储的PSQL程序?

或者请指出如何计算。

1 个答案:

答案 0 :(得分:2)

如果我理解你的任务,你需要递归调用。函数取first的第一行并逐个处理。

WITH RECURSIVE x AS (
   SELECT *
     FROM (
            SELECT item_id,
                   item_datetime,
                   item_datetime + (item_duration_in_days::text || ' day')::interval AS cur_end
              FROM ti
             ORDER BY item_datetime
             LIMIT 1
          ) AS first
   UNION ALL
   SELECT item_id,
          cur_start,
          cur_start + (item_duration_in_days::text || ' day')::interval
     FROM (
            SELECT item_id,
                   CASE WHEN item_datetime > prev_end THEN
                            item_datetime
                        ELSE
                            prev_end
                        END AS cur_start,
                   item_duration_in_days
              FROM (
                     SELECT ti.item_id,
                            ti.item_datetime,
                            x.cur_end + '1 day'::interval AS prev_end,
                            item_duration_in_days
                       FROM x
                       JOIN ti ON (
                               ti.item_id != x.item_id
                               AND ti.item_datetime >= x.item_datetime
                            )
                      ORDER BY ti.item_datetime
                      LIMIT 1
                    ) AS a
          ) AS a
) SELECT * FROM x;

结果:

 item_id |    item_datetime    |       cur_end       
---------+---------------------+---------------------
       1 | 2016-12-07 12:00:00 | 2016-12-10 12:00:00
       2 | 2016-12-11 12:00:00 | 2016-12-15 12:00:00
       3 | 2016-12-20 05:00:00 | 2016-12-30 05:00:00
       4 | 2017-01-02 14:00:00 | 2017-02-21 14:00:00
       5 | 2017-02-22 14:00:00 | 2017-05-22 14:00:00
(5 rows)

查看当前的工作:

....
) SELECT * FROM x WHERE item_datetime <= now() AND cur_end >= now();

 item_id |    item_datetime    |       cur_end       
---------+---------------------+---------------------
       4 | 2017-01-02 14:00:00 | 2017-02-21 14:00:00
(1 row)