2016-10-31 4 views
1

最近私はpostgresを使用し始めました。私はoracleのバックグラウンドから来ています。ちょうど私が書いたクエリがポストグルでより良い方法で実装できるかどうかを知りたいのは興味があります。監視されたプログラムカテゴリに基づいてレコードを複数のレコードに分割します

問題の詳細:

  1. PROGRAM_INFO

Usage_detailはチャンネルを見ているすべてのユーザーに関する情報を持っている

  • usage_detail:

    は、私は2つのテーブルを持っています。例えば、ユーザA、1時間10分0秒だったそのセッションの長さのために、今日の13:15から始まる

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

    PROGRAM_INFOテーブルは、スケジュールされたプログラムの詳細と対応するカテゴリが含まれています。例えば

    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時25分、午後2時から午後2時25分まで)、program_category 。

    私は、あまり読みにくいコードを書いています。これは、postgresの配列とネストされていない機能を使用せずに、1つのレコードから複数のレコードを動的に生成します。

    誰もが、この問題にアプローチする最も良い方法は、Array/UnnestやPostgresで利用可能な他の機能を使用して提案することはできますか?私は正確なコードを探しているわけではなく、方向だけがあります。

    +1

    私の世界では、2016-10-31は月曜日ではなく日曜日です。 –

    +0

    少し後でそれを認識して編集します。インドのディワリ時間、休暇は日曜日のように感じられます。 :D – KSN

    答えて

    1

    私はあなたが行を生成する必要はないと思う。サンプルデータに基づいて、2つのテーブルを単純に結合することができます。

    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) 
    

    to_char(ud.start_time, 'FMday') = lower(pi.week_day)を使用して参加がto_char()がそれを返すであろうと同じ言語で格納される曜日を必要とすること

    注(userは予約キーワードであるので、私は、user_name代わりにuserを使用)。文字列ではなく数値として格納する方がよいでしょう。

    その結果、各プログラムの実際の開始時刻と終了時刻を計算することができます。これは、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です。上記戻り、この:範囲は、今あなたが望む最終的な表示を取得するために使用することができるよう

    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) 
    

    は、実際の視聴時間を持つ:

    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 
    

    オンライン例:http://rextester.com/VNXIG64065

    +0

    すごいもの、ありがとう。私は時間の境界条件(23:45から00:15)に関して少し変更を加えなければならなかったが、上限が翌日の時間であることを理解できないのでエラーを出した。私はそれに日付部分を追加し、inbuilt tsrangeを使用し、すべてが働いた。 – KSN

    関連する問題