Postgresql:tsrange之间的空隙,空集

时间:2014-06-24 21:15:01

标签: sql database postgresql

我有一个每个用户的预订表:

reservations_development=# \d reservations
                           Table "public.reservations"
   Column   |  Type   |                         Modifiers
------------+---------+-----------------------------------------------------------
 id         | integer | not null default nextval('reservations_id_seq'::regclass)
 user_id    | integer |
 occurrence | tsrange |
Indexes:
    "reservations_pkey" PRIMARY KEY, btree (id)
    "reservations_occurrence_user_id_excl" EXCLUDE USING gist (occurrence WITH &&, user_id WITH =)

我正在尝试创建每个用户的预订之间的差距/开放视图,我目前有以下查询:

CREATE OR REPLACE VIEW reservation_gaps AS (
        with user_mins as (select tsrange(LOCALTIMESTAMP, min(lower(occurrence))), user_id
                FROM (
                    SELECT user_id, occurrence
                    FROM reservations
                    WHERE lower(occurrence) >= LOCALTIMESTAMP
                ) as y
                GROUP BY user_id
        ),
        gaps as (select
                tsrange(upper(occurrence), lead(lower(occurrence),1, LOCALTIMESTAMP + interval '1 year') over (win_user_gaps)),
                user_id
                from (
                        select user_id, occurrence
                        from reservations
                ) as x
                WINDOW win_user_gaps AS (PARTITION BY user_id ORDER BY occurrence)
                UNION ALL SELECT * FROM user_mins
        )
        select *
        FROM gaps
        ORDER BY user_id, tsrange
);

只要用户有一个预订,它目前会给出预期的结果,但如果用户是新的,并且当前没有被保留,我会得到一个空的结果。

我需要以某种方式将{tsrange(LOCALTIMESTAMP,LOCALTIMESTAMP +间隔' 1年'),user_id}行附加到每个用户的视图中,而无需预订,但我目前正在难以理解如何做到这一点。

由于

2 个答案:

答案 0 :(得分:0)

您应该使用人工行将CTE更改为UNION ALL,然后使用DISTINCT ON为每个用户选择一行。

with user_mins as (SELECT DISTINCT ON (user_id) user_id, tsrange FROM(
select tsrange(LOCALTIMESTAMP, min(lower(occurrence))) as tsrange, user_id, 1 as priotity
                FROM (
                    SELECT user_id, occurrence
                    FROM reservations
                    WHERE lower(occurrence) >= LOCALTIMESTAMP
                ) as y
                GROUP BY user_id
                UNION ALL
                SELECT user_id,  tsrange(LOCALTIMESTAMP, LOCALTIMESTAMP + interval '1 year'),                     
                0
                FROM users)
        ORDER BY user_id, priority DESC
)

答案 1 :(得分:0)

SQL Fiddle

with this_year as (
    select tsrange(
        date_trunc('year', current_date)::timestamp,
        date_trunc('year', current_date)::timestamp + interval '1' year, '[)'
    ) as this_year
), gaps as (
    select
        user_id,
        this_year - tsrange(lower(occurrence), 'infinity', '[]') lower_range,
        this_year - tsrange('-infinity', upper(occurrence), '[]') upper_range,
        this_year
    from
        reservations
        cross join
        this_year
)
select *
from (
    select
        user_id,
        upper_range *
            lead (lower_range, 1, this_year)
            over (partition by user_id order by lower_range, upper_range)
        as gap
    from gaps
    union (
        select distinct on (user_id)
            user_id,
            tsrange(
                lower(this_year),
                coalesce(upper(lower_range), upper(this_year)),
                '[)'
            ) as gap
        from gaps
        order by user_id, lower_range
    )
) s
where gap != 'empty'
order by user_id, gap