sql >> データベース >  >> RDS >> PostgreSQL

SQLで同時イベントの数を計算する

    可能なオーバーラップは次のようになります。ここで、「A」は「参照」間隔です。以下のクエリ(はるかに下)では、まだ投稿されている回答と同じ結果が得られないことに注意してください。

    -- A            |------|
    -- B |-|
    -- C        |---|
    -- D          |---|
    -- E             |---|
    -- F               |---|
    -- G                 |---|
    -- H                   |---|
    -- I                       |---|
    

    「B」は「A」とまったく重なりません。 「C」が隣接しています。 {"D"、 "E"、 "F"、"G"}が重なっています。 「H」が隣接しています。 「私」はそれとまったく重ならない。

    create table calls_nov (
      sid varchar(5) primary key,
      starttime timestamp not null,
      endtime timestamp not null
    );  
    
    insert into calls_nov values
    ('A', '2012-01-04 08:00:00', '2012-01-04 08:00:10'),
    ('B', '2012-01-04 07:50:00', '2012-01-04 07:50:03'),
    ('C', '2012-01-04 07:59:57', '2012-01-04 08:00:00'),
    ('D', '2012-01-04 07:59:57', '2012-01-04 08:00:03'),
    ('E', '2012-01-04 08:00:01', '2012-01-04 08:00:04'),
    ('F', '2012-01-04 08:00:07', '2012-01-04 08:00:10'),
    ('G', '2012-01-04 08:00:07', '2012-01-04 08:00:13'),
    ('H', '2012-01-04 08:00:10', '2012-01-04 08:00:13'),
    ('I', '2012-01-04 08:00:15', '2012-01-04 08:00:18');
    

    このように重なり合う間隔をすべて見ることができます。 (to_char()を使用して、すべてのデータを簡単に確認できるようにしました。本番環境では省略できます。)

    select t1.sid, to_char(t1.starttime, 'HH12:MI:SS'), 
                   to_char(t1.endtime,   'HH12:MI:SS'), 
           t2.sid, to_char(t2.starttime, 'HH12:MI:SS'), 
                   to_char(t2.endtime,   'HH12:MI:SS')
    from calls_nov t1
    inner join calls_nov t2 on (t2.starttime, t2.endtime) 
                      overlaps (t1.starttime, t1.endtime) 
    order by t1.sid, t2.sid;
    
    A   08:00:00   08:00:10   A   08:00:00   08:00:10
    A   08:00:00   08:00:10   D   07:59:57   08:00:03
    A   08:00:00   08:00:10   E   08:00:01   08:00:04
    A   08:00:00   08:00:10   F   08:00:07   08:00:10
    A   08:00:00   08:00:10   G   08:00:07   08:00:13
    B   07:50:00   07:50:03   B   07:50:00   07:50:03
    C   07:59:57   08:00:00   C   07:59:57   08:00:00
    C   07:59:57   08:00:00   D   07:59:57   08:00:03
    D   07:59:57   08:00:03   A   08:00:00   08:00:10
    D   07:59:57   08:00:03   C   07:59:57   08:00:00
    D   07:59:57   08:00:03   D   07:59:57   08:00:03
    D   07:59:57   08:00:03   E   08:00:01   08:00:04
    E   08:00:01   08:00:04   A   08:00:00   08:00:10
    E   08:00:01   08:00:04   D   07:59:57   08:00:03
    E   08:00:01   08:00:04   E   08:00:01   08:00:04
    F   08:00:07   08:00:10   A   08:00:00   08:00:10
    F   08:00:07   08:00:10   F   08:00:07   08:00:10
    F   08:00:07   08:00:10   G   08:00:07   08:00:13
    G   08:00:07   08:00:13   A   08:00:00   08:00:10
    G   08:00:07   08:00:13   F   08:00:07   08:00:10
    G   08:00:07   08:00:13   G   08:00:07   08:00:13
    G   08:00:07   08:00:13   H   08:00:10   08:00:13
    H   08:00:10   08:00:13   G   08:00:07   08:00:13
    H   08:00:10   08:00:13   H   08:00:10   08:00:13
    I   08:00:15   08:00:18   I   08:00:15   08:00:18
    

    この表から、「A」はそれ自体を含めて5を数える必要があることがわかります。 「B」は1を数える必要があります。それ自体はオーバーラップしますが、他の間隔はオーバーラップしません。それは正しいことのようです。

    カウントは簡単ですが、カメが破裂したように走ります。これは、オーバーラップの評価に多くの作業が必要になるためです。

    select t1.sid, count(t2.sid) as num_concurrent
    from calls_nov t1
    inner join calls_nov t2 on (t2.starttime, t2.endtime) 
                      overlaps (t1.starttime, t1.endtime) 
    group by t1.sid
    order by num_concurrent desc;
    
    A   5
    D   4
    G   4
    E   3
    F   3
    H   2
    C   2
    I   1
    B   1
    

    パフォーマンスを向上させるために、一般的なテーブル式で上記の「テーブル」を使用し、そのに基づいてカウントすることができます。 。

    with interval_table as (
    select t1.sid as sid_1, t1.starttime, t1.endtime,
           t2.sid as sid_2, t2.starttime, t2.endtime
    from calls_nov t1
    inner join calls_nov t2 on (t2.starttime, t2.endtime) 
                      overlaps (t1.starttime, t1.endtime) 
    order by t1.sid, t2.sid
    ) 
    select sid_1, count(sid_2) as num_concurrent
    from interval_table
    group by sid_1
    order by num_concurrent desc;
    


    1. Oracleトラブルのパラメータ化されたクエリ

    2. 科学的記数法なしでSQLServerでfloatをvarcharに変換する

    3. 特定の条件下でINSERTを防止するMySQLトリガー

    4. PostgreSQLは構成/confファイルをどこに保存しますか?