2014-06-24 2 views
0

나는 각 사용자에 대한 예약의 테이블이 있습니다PostgreSQL을 : tsranges 사이 간격 하늘 세트

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 + interval '1 year'), user_id} 행을 추가해야하지만 현재 어떻게해야하는지 잘 모르겠습니다. 그.

감사

답변

0

당신은 인공 행이 UNION ALL하고 다음 사용자 당 하나 개의 행을 선택 DISTINCT ON를 사용하도록 CTE를 변경해야합니다.

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 
) 
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