2016-10-31 12 views
1

최근 포스트그레스를 사용하기 시작했으며 오라클 백그라운드에서 왔습니다. 내가 작성한 질의가 포스트 그레스에서보다 나은 방법으로 구현 될 수 있는지 궁금하다.감시 된 프로그램 범주를 기반으로 레코드를 여러 레코드로 나눕니다.

문제점 세부 사항 :

  1. Program_info

Usage_detail이 채널을 시청하는 사용자에 대한 정보를 가지고

  • usage_detail :

    나는 두 개의 테이블이있다. 예를 들어 사용자에 대한 오늘날

    User start_time   end_time 
    A  2016-10-31 13:15:00 2016-10-31 14:25:00 
    

    Program_info 테이블이 포함 예약 프로그램 세부시 15 시작 카테고리에 대응하는 10 분 1 시간 0초 그것의 세션 길이를 가지고 있었다. 예를 들어

    는 :

    Program_id program_category week_day start_time end_time 
         1 News    Monday  13:00  13:30 
         2 Sports   Monday  13:30  14:30 
    

    내가 찾고 있어요 출력은 다음과 같습니다

    User program_category start_time   duration (in seconds) 
        A News    2016-10-31 13:15:00  900 
        A Sports    2016-10-31 13:30:00  3300 
    

    나의 현재 접근 방식 : 나는 30 분 간격으로 START_TIME 및 END_TIME 기간을 나누어

    (때문에 프로그램 카테고리는 매 30 분마다 변경 될 수 있음). 언급 한 예와 마찬가지로, 나는 처음에 3 개의 레코드 (오후 1시 15 분 -1시 30 분 오후 1시 30 분 - 오후 2시, 오후 2시 - 오후 2시 25 분)를 작성한 후 program_category .

    필자는 좀 덜 읽기 쉬운 코드를 작성하여 postgres의 배열 및 불감 복사 기능을 사용하지 않고 하나의 레코드에서 여러 레코드를 동적으로 생성합니다.

    누구든지 배열/중첩 또는 포스트 그레스에서 사용할 수있는 다른 기능을 사용하여이 문제에 접근하는 가장 좋은 방법을 제안 할 수 있습니까? 나는 정확한 코드를 찾지 않고 있으며 방향 만 알면된다.

    +1

    세계에서 2016-10-31은 월요일이 아니며 일요일이 아닙니다. –

    +0

    조금 나중에 깨닫고 편집 할 것입니다. 인도의 디 왈리 (Diwali) 시간, 휴가는 일요일처럼 느껴집니다. : D – KSN

    답변

    1

    나는 어떤 행도 생성 할 필요가 없다고 생각합니다. 샘플 데이터를 기반으로 두 테이블을 간단하게 결합 할 수 있습니다. to_char(ud.start_time, 'FMday') = lower(pi.week_day)를 사용하여 조인

    주를 반환합니다 to_char()와 같은 언어로 저장 할 수있는 요일을 필요로

    select * 
    from program_info pi 
        join usage_detail ud 
        on to_char(ud.start_time, 'FMday') = lower(pi.week_day) 
        and (pi.start_time, pi.end_time) overlaps (ud.start_time::time, ud.end_time::time) 
    

    은 ( user는 예약 키워드이기 때문에 내가 대신 useruser_name를 사용). 숫자가 아닌 문자열로 저장하는 것이 좋습니다.

    그 결과 각 프로그램의 실제 시작 시간과 종료 시간을 계산할 수 있습니다. 이것은 usage_detail에 저장된 시간 정보와 program_info에 저장된 시간 정보를 비교하여 시작 시간 중 더 큰 시간과 종료 시간 중 작은 시간을 비교하는 복잡한 case when 문을 사용하여 수행 할 수 있습니다.

    그러나 이것은 시간 범위를 사용하여 간단하게 할 수 있습니다.불행하게도, 거기에 내장 그러한 범위 시간은 없지만, 그것은 쉽게 만들 수 있습니다 :

    select ud.user_name, 
         pi.program_id, 
         pi.program_category, 
         ud.start_time::date as start_day, 
         timerange(pi.start_time, pi.end_time) * timerange(ud.start_time::time, ud.end_time::time) as view_interval 
    from program_info pi 
        join usage_detail ud 
        on to_char(ud.start_time, 'FMday') = lower(pi.week_day) 
        and (pi.start_time, pi.end_time) overlaps (ud.start_time::time, ud.end_time::time) 
    

    : 실제 시작 시간과 종료 시간이 두 범위의 교차점을 사용하여 계산 될 수와

    create type timerange as range (subtype = time); 
    

    *은 범위의 경우 intersection operator입니다. 위의 반환이 :

    with view_times as (
        select ud.user_name, 
          pi.program_id, 
          pi.program_category, 
          ud.start_time::date as start_day, 
          timerange(pi.start_time, pi.end_time) * timerange(ud.start_time::time, ud.end_time::time) as view_interval 
        from program_info pi 
         join usage_detail ud 
         on to_char(ud.start_time, 'FMday') = lower(pi.week_day) 
         and (pi.start_time, pi.end_time) overlaps (ud.start_time::time, ud.end_time::time) 
    ) 
    select user_name, program_id, program_category, 
         start_day + lower(view_interval) as actual_start_time, 
         extract(epoch from (upper(view_interval) - lower(view_interval))) as duration 
    from view_times 
    

    이 반환 :

    user_name | program_id | program_category | actual_start_time | duration 
    ----------+------------+------------------+---------------------+--------- 
    A   |   1 | News    | 2016-10-31 13:15:00 |  900 
    A   |   2 | Sports   | 2016-10-31 13:30:00 |  3300 
    

    온라인을 범위로 실제 시청 시간을 갖는

    user_name | program_id | program_category | start_day | view_interval  
    ----------+------------+------------------+------------+-------------------- 
    A   |   1 | News    | 2016-10-31 | [13:15:00,13:30:00) 
    A   |   2 | Sports   | 2016-10-31 | [13:30:00,14:25:00) 
    

    지금 당신이 원하는 최종 디스플레이를 가져올 수 있습니다 예 : http://rextester.com/VNXIG64065

    +0

    굉장한 물건, 고맙다. 시간 경계 조건 (23:45 ~ 00:15)에 대해서는 사소한 변화가 있었지만, 상한선이 다음날 동안인지 이해할 수 없으므로 오류가 발생했습니다. 나는 날짜 부분을 추가하고, inbuilt tsrange를 사용했으며 모든 것이 잘 작동했다. – KSN