背景(入力)
Global Historical Climatology Networkは、気象測定値のコレクションで無効または誤ったデータにフラグを立てました。これらの要素を削除した後、連続した日付のセクションがなくなった一連のデータがあります。データは次のようになります。
"2007-12-01";14 -- Start of December
"2007-12-29";8
"2007-12-30";11
"2007-12-31";7
"2008-01-01";8 -- Start of January
"2008-01-02";12
"2008-01-29";0
"2008-01-31";7
"2008-02-01";4 -- Start of February
... entire month is complete ...
"2008-02-29";12
"2008-03-01";14 -- Start of March
"2008-03-02";17
"2008-03-05";17
問題(出力)
欠落しているデータを推定して (たとえば、他の年から平均することによって) 連続した範囲を提供することは可能ですが、システムを簡素化するために、月を埋める連続した日付範囲があるかどうかに基づいて、連続していないセグメントにフラグを立てたいと考えています。
D;"2007-12-01";14 -- Start of December
D;"2007-12-29";8
D;"2007-12-30";11
D;"2007-12-31";7
D;"2008-01-01";8 -- Start of January
D;"2008-01-02";12
D;"2008-01-29";0
D;"2008-01-31";7
"2008-02-01";4 -- Start of February
... entire month is complete ...
"2008-02-29";12
D;"2008-03-01";14 -- Start of March
D;"2008-03-02";17
D;"2008-03-05";17
1843 年にいくつかの測定が行われました。
質問
すべての測候所について、1 日以上欠落している月のすべての日をどのようにマークしますか?
ソースコード
データを選択するコードは次のようになります。
select
m.id,
m.taken,
m.station_id,
m.amount
from
climate.measurement
関連するアイデア
連続した日付で満たされたテーブルを生成し、それらを測定データの日付と比較します。
- (mysql または perl 側で) SQL の結果に空の日付を埋め込む最も簡単な方法は何ですか?
- 連続範囲でグループ化する方法
- http://msdn.microsoft.com/en-us/library/aa175780%28v=sql.80%29.aspx
アップデート
この問題は、このセクションの SQL を使用して再現できます。
テーブル
テーブルは次のように作成されます。
CREATE TABLE climate.calendar
(
id serial NOT NULL,
n character varying(2) NOT NULL,
d date NOT NULL,
"valid" boolean NOT NULL DEFAULT true,
CONSTRAINT calendar_pk PRIMARY KEY (id)
)
WITH (
OIDS=FALSE
);
データの生成
次の SQL は、テーブルにデータを挿入します ( id
[int]、n
ame [varchar]、d
ate [date]、valid
[boolean]):
insert into climate.calendar (n, d)
select 'A', (date('1982-01-1') + (n || ' days')::interval)::date cal_date
from generate_series(0, date('2011-04-9') - date('1982-01-1') ) n
insert into climate.calendar (n, d)
select 'B', (date('1982-01-1') + (n || ' days')::interval)::date cal_date
from generate_series(0, date('2011-04-9') - date('1982-01-1') ) n
insert into climate.calendar (n, d)
select 'C', (date('1982-01-1') + (n || ' days')::interval)::date cal_date
from generate_series(0, date('2011-04-9') - date('1982-01-1') ) n
insert into climate.calendar (n, d)
select 'D', (date('1982-01-1') + (n || ' days')::interval)::date cal_date
from generate_series(0, date('2011-04-9') - date('1982-01-1') ) n
insert into climate.calendar (n, d)
select 'E', (date('1982-01-1') + (n || ' days')::interval)::date cal_date
from generate_series(0, date('2011-04-9') - date('1982-01-1') ) n
insert into climate.calendar (n, d)
select 'F', (date('1982-01-1') + (n || ' days')::interval)::date cal_date
from generate_series(0, date('2011-04-9') - date('1982-01-1') ) n
~の値は、特定の日に測定を行った気象観測所の名前'A'
を表します。'F'
ランダムな行を削除
次のようにいくつかの行を削除します。
delete from climate.calendar where id in (select id from climate.calendar order by random() limit 5000);
試み #1
次の例では、月に 1 日以上欠落しているすべての日に対してvalid
フラグを切り替えません。false
UPDATE climate.calendar
SET valid = false
WHERE date_trunc('month', d) IN (
SELECT DISTINCT date_trunc('month', d)
FROM climate.calendar A
WHERE NOT EXISTS (
SELECT 1
FROM climate.calendar B
WHERE A.d - 1 = B.d
)
);
試み #2
次の SQL は、空の結果セットを生成します。
with gen_calendar as (
select (date('1982-01-1') + (n || ' days')::interval)::date cal_date
from generate_series(0, date('2011-04-9') - date('1982-01-1') ) n
)
select gc.cal_date
from gen_calendar gc
left join climate.calendar c on c.d = gc.cal_date
where c.d is null;
試み #3
次の SQL は、駅名と日付の可能な組み合わせをすべて生成します。
select
distinct( cc.n ), t.d
from
climate.calendar cc,
(
select (date('1982-01-1') + (n || ' days')::interval)::date d
from generate_series(0, date('2011-04-9') - date('1982-01-1') ) n
) t
order by
cc.n
ただし、実際のデータには数百の測点があり、日付は 1800 年代半ばまでさかのぼるため、すべての測点のすべての日付のデカルトは大きすぎます。このようなアプローチは、十分な時間があればうまくいくかもしれません...もっと速い方法があるはずです。
試み #4
PostgreSQL にはウィンドウ関数があります。
postgres でウィンドウ関数を使用して特定の変更を選択する方法
ありがとうございました!