7

次の表があるとします。

CREATE TABLE channel1m (
  ts TIMESTAMP WITHOUT TIME ZONE NOT NULL,
  itemId BIGINT,
  value BIGINT
)

次のように、itemIdごとに1ごとに行挿入できます。

ts                    itemId         value
2012-12-03 15:29:00   100            1
2012-12-03 15:30:00   100            2
2012-12-03 15:30:00   101            0
2012-12-03 15:32:00   100            1
2012-12-03 15:32:00   101            1

値を返すことで時間のギャップ(たとえば、itemId 101の場合は15:29:00、両方のアイテムの場合は15:31:00)を埋めるクエリを作成する方法を(追加のテーブルを作成せずに)見つけることができませんNULL

期待される結果セットは次のようになります。

ts                    itemId         value
2012-12-03 15:29:00   100            1
2012-12-03 15:29:00   101            NULL
2012-12-03 15:30:00   100            2
2012-12-03 15:30:00   101            0
2012-12-03 15:31:00   100            NULL
2012-12-03 15:31:00   101            NULL
2012-12-03 15:32:00   100            1
2012-12-03 15:32:00   101            1

一連のタイムスタンプを含む個別のタイムテーブルを持つソリューションを見つけましたが、クエリだけでこれを解決したいと思います。これは可能ですか?

4

4 に答える 4

11
DROP SCHEMA tmp CASCADE;
CREATE SCHEMA tmp ;
SET search_path = tmp;

DROP TABLE IF EXISTS channel1m CASCADE;
CREATE TABLE channel1m (
  zts TIMESTAMP WITHOUT TIME ZONE NOT NULL,
  zitemid BIGINT,
  zvalue BIGINT
);

-- in which a row may be inserted each minute, per zitemid, as follows:

INSERT INTO channel1m(zts, zitemid, zvalue) VALUES
 ('2012-12-03 15:29:00',   100,            1)
,('2012-12-03 15:30:00',   100,            2)
,('2012-12-03 15:30:00',   101,            0)
,('2012-12-03 15:32:00',   100,            1)
,('2012-12-03 15:32:00',   101,            1)
        ;

        -- CTE to the rescue!!!
WITH cal AS (
        WITH mm AS (
                SELECT MIN(xx.zts) AS minmin, MAX(xx.zts) AS maxmax
                 FROM channel1m xx)
        SELECT generate_series(mm.minmin , mm.maxmax , '1 min'::interval) AS stamp
        FROM mm
        )
, ite AS (
        SELECT DISTINCT zitemid AS zitemid
        FROM channel1m
        )
SELECT cal.stamp
        , ite.zitemid
        , tab.zvalue
FROM cal
JOIN ite ON 1=1 -- Note: this is a cartesian product of the {time,id} -domains
LEFT JOIN channel1m tab ON tab.zts = cal.stamp AND tab.zitemid = ite.zitemid
ORDER BY stamp ASC
        ;

出力:

NOTICE:  drop cascades to table tmp.channel1m
DROP SCHEMA
CREATE SCHEMA
SET
NOTICE:  table "channel1m" does not exist, skipping
DROP TABLE
CREATE TABLE
INSERT 0 5
        stamp        | zitemid | zvalue 
---------------------+---------+--------
 2012-12-03 15:29:00 |     101 |       
 2012-12-03 15:29:00 |     100 |      1
 2012-12-03 15:30:00 |     100 |      2
 2012-12-03 15:30:00 |     101 |      0
 2012-12-03 15:31:00 |     100 |       
 2012-12-03 15:31:00 |     101 |       
 2012-12-03 15:32:00 |     100 |      1
 2012-12-03 15:32:00 |     101 |      1
(8 rows)
于 2012-12-05T17:22:38.040 に答える
7

必要なもの:すべてitemIdのテーブルと、必要なすべての日付の(疑似)テーブル。

おそらく、すべてが異なるテーブルがありますitemId。それを呼びましょうitem_table

で取得できる日付の疑似テーブルgenerate_series('start_date','end_date', interval '1 minute')。詳細はこちら

クエリ:

SELECT gs.ts, it.itemId, ch1m.value
FROM item_table it
CROSS JOIN generate_series('start_date','end_date', interval '1 minute') gs(ts)
LEFT JOIN channel1m ch1m ON it.itemId = ch1m.itemId 
                         AND gs.ts = ch1m.ts

目的の値に置き換える'start_date','end_date'か、サブクエリから取得します。

このクエリ:

1)アイテム時間のすべてのペアをCROSS JOIN

value2)ビアを取得しますLEFT JOIN

于 2012-12-05T17:20:25.887 に答える
1

最も読みやすい方法は、一連のテーブル式を作成することだと思います。分とアイテムID番号の間のクロス結合は、すべての組み合わせを提供します。

with all_minutes as (
  select ('2012-12-03 15:29'::timestamp + 
           (n || ' minute')::interval)::timestamp as ts
  from generate_series(0,10) n
),
item_ids as (
  select distinct itemid from channel1m
),
all_items_and_minutes as (
  select all_minutes.ts, item_ids.itemid from all_minutes cross join item_ids
)
select all_items_and_minutes.ts, all_items_and_minutes.itemId, channel1m.value
from all_items_and_minutes 
left join channel1m 
       on all_items_and_minutes.ts = channel1m.ts
      and all_items_and_minutes.itemid = channel1m.itemid
order by all_items_and_minutes.ts, all_items_and_minutes.itemid

タイムスタンプリテラルをSELECTステートメントに置き換えて、必要な実際の範囲を取得できます。すべての一意のアイテムID番号を含む別のテーブルがある場合は、channel1mテーブルから個別の値を選択するのではなく、そのテーブルから選択する方がよい場合があります。

于 2012-12-05T17:28:32.637 に答える
0
  1. time_bucketまたはを使用date_truncしてバケット境界を作成します。
  2. generate_series時間枠の空のバケットを生成するために使用します。
  3. UNION空のタイムバケットデータセットをデータとマージするために使用します。
  4. DISTINCT ONタイムバケットごとに一意の行を選択するために使用し、データのある行を優先します。

例:

WITH
  timeseries_data AS (
    SELECT
      time_bucket(interval '5 minutes', started_at) time_bucket_start,
      count(distinct v1.value) unique_row_count
    FROM
      probe_execution pe1
    CROSS JOIN LATERAL (
      SELECT value
      FROM jsonb_array_elements(pe1.result)
    ) v1
    WHERE
      pe1.probe_id = 8 AND
      pe1.result_count > 0 AND
      pe1.started_at > now() - interval '1 day' AND
      pe1.ended_at < now()
    GROUP BY time_bucket_start
    UNION
    SELECT
      gs1 time_bucket_start,
      0 unique_row_count
    FROM
      generate_series(
        time_bucket(interval '5 minutes', now() - interval '1 day'),
        time_bucket(interval '5 minutes', now()),
        interval '1 minute'
      ) as gs1
  )
SELECT DISTINCT ON (td1.time_bucket_start)
  td1.time_bucket_start,
  td1.unique_row_count
FROM timeseries_data td1
ORDER BY td1.time_bucket_start, td1.unique_row_count DESC
于 2019-03-03T18:43:08.353 に答える