过滤生成结果的SQL查询

时间:2017-02-03 07:11:47

标签: sql postgresql

我有一个plpgsql函数,它根据名为timeslots的表中存储的规则在两个日期之间生成TSTZRANGE。它工作正常,但现在我得到了一个新的要求,并在datespan表中添加了一个名为timeslots的TSTZRANGE字段,我还需要对其进行过滤,以便只返回此字段值中包含的范围。

在这里展示我需要改变的部分功能。 eidfromdatetodate是传递给函数的参数。

SELECT TSTZRANGE(
    (series::DATE + ts1.start)::TIMESTAMPTZ AT TIME ZONE 'UTC',
    (series::DATE + ts1.end)::TIMESTAMPTZ AT TIME ZONE 'UTC'
) AS range
FROM
  timeslots AS ts1,
  generate_series(fromdate, todate, '1 day') AS series
WHERE
  eid = ts1.event_id AND
  EXTRACT(DOW FROM series) = ANY(ts1.weekdays)
ORDER BY
  range

所以我想要做的是添加一个像WHERE range <@ ts1.datespan这样的过滤器,但我无法将它放在任何可行的地方。

实施例: 在timeslots表中提供此信息:

 id |  start   |   end    |   weekdays    | event_id |           datespan 
----+----------+----------+---------------+----------------------------------------------------------------
 1  | 12:00:00 | 14:00:00 | {1,2,3,5,6,0} |       1  | ["2017-01-01 00:00:00+00","2017-02-01 00:00:00+00")
 2  | 09:00:00 | 11:00:00 | {1,2,3,5,6,0} |       1  | [null, null)
 3  | 15:00:00 | 17:00:00 | {1,2,3,5,6,0} |       1  | ["2017-02-01 00:00:00+00","2017-03-01 00:00:00+00")

如果eid=1fromdate='2017-02-02'todate='2017-02-03'如下所示,则调用上面的SELECT的结果如下:

                        range                        
-----------------------------------------------------
 ["2017-02-02 09:00:00+00","2017-02-02 11:00:00+00")
 ["2017-02-02 15:00:00+00","2017-02-02 17:00:00+00")
 ["2017-02-03 09:00:00+00","2017-02-03 11:00:00+00")
 ["2017-02-03 15:00:00+00","2017-02-03 17:00:00+00")

1 个答案:

答案 0 :(得分:1)

最简单的方法是使用lateral

  

LATERAL关键字可以在子SELECT FROM项之前。这允许子SELECT引用FROM列表中出现在它之前的FROM项列。 (如果没有LATERAL,每个子SELECT都是独立评估的,因此不能交叉引用任何其他FROM项。)

select ts1.*, range
from
    timeslots as ts1,
    generate_series('2017-02-02'::date, '2017-02-03', '1 day') as series
    cross join lateral
    (
        select tstzrange (
            (series::date + ts1.start)::timestamptz at time zone 'utc',
            (series::date + ts1.end)::timestamptz at time zone 'utc'
        ) as range
    ) range
where
    1 = ts1.event_id and
    extract(dow from series) = any(ts1.weekdays) and
    range <@ ts1.datespan
order by range
;
 id |  start   |   end    |   weekdays    | event_id |                      datespan                       |                        range                        
----+----------+----------+---------------+----------+-----------------------------------------------------+-----------------------------------------------------
  2 | 09:00:00 | 11:00:00 | {1,2,3,5,6,0} |        1 | (,)                                                 | ["2017-02-03 09:00:00+00","2017-02-03 11:00:00+00")
  3 | 15:00:00 | 17:00:00 | {1,2,3,5,6,0} |        1 | ["2017-02-01 00:00:00+00","2017-03-01 00:00:00+00") | ["2017-02-03 15:00:00+00","2017-02-03 17:00:00+00")

另一种方法是将其包装在外部查询中。现在您需要决定/告知如何处理空边界。