SQLパズル:NULLの埋め立て

 全国のプロフェッショナルなDBエンジニアおよび別にデータベースが専門じゃないけど開発の成り行きでデータベースを触ることになってしまったプログラマの皆さん、お元気ですか。今月もSQLパズルの時間がやってまいりました。「え? いつ月例に?」と思った向きはご存知ないでしょうが、こないだ理事長権限で毎月開かれることに決まったのです。理事長は今日は丹念にキーボードの掃除をしてすごしました。キーを一つ一つはずして綺麗にふき、中にたまっているゴミを取り出していると、これもなかなか明確な終わりのない作業で、気づいたら日中ほとんどの時間を費やしてしまった。決してヒマなわけではないのだけどあまり説得力はないな。

 さて、今月のお題は、「更新」です。サンプルデータは以下のもの。


CREATE TABLE OmitTbl
(keycol CHAR(8) NOT NULL,
seq INTEGER NOT NULL,
val INTEGER ,
PRIMARY KEY (keycol, seq));

INSERT INTO OmitTbl VALUES ('A', 1, 50);
INSERT INTO OmitTbl VALUES ('A', 2, NULL);
INSERT INTO OmitTbl VALUES ('A', 3, NULL);
INSERT INTO OmitTbl VALUES ('A', 4, 70);
INSERT INTO OmitTbl VALUES ('A', 5, NULL);
INSERT INTO OmitTbl VALUES ('A', 6, 900);

INSERT INTO OmitTbl VALUES ('B', 1, 10);
INSERT INTO OmitTbl VALUES ('B', 2, 20);
INSERT INTO OmitTbl VALUES ('B', 3, NULL);
INSERT INTO OmitTbl VALUES ('B', 4, 3);
INSERT INTO OmitTbl VALUES ('B', 5, NULL);
INSERT INTO OmitTbl VALUES ('B', 6, NULL);


 keycol(キー) + seq(連番)で一意な、何の変哲もないテーブルです。注目して欲しいのは、valがNULLの行。これは、本当は値はあるのだけど、前のレコード(同じkeycolで連番が一つ前)と同じ値のため省略されているのです。紙をパンチして電子データを作る場合なんかに、タイプ回数を減らすためにこういう省略措置がよく行われます。

 人間ならそういうルールと知っていればすぐわかるのでいいのですが、データベースに投入して集計したい場合には、このままだと使い物になりません。律儀に埋めてやらないといけない。そこで、次のようにNULLの行を「埋めた」テーブルを作ってください。


/* 求める結果 */
KEYCOL SEQ VAL
―――― ―――――― ―――――
A 1 50
A 2 50 ←埋めた
A 3 50 ←埋めた
A 4 70
A 5 70 ←埋めた
A 6 900
B 1 10
B 2 20
B 3 20 ←埋めた
B 4 3
B 5 3 ←埋めた
B 6 3 ←埋めた

 レベルとしては、「中の中」、かな。『SQLパズル』によく似た問題があるので、既読の方はすぐにぴんときたかも。条件は、いつもどおり、カーソルやホスト言語は使わずに、ピュアSQLで(実装依存の機能は使用可)。とりあえず私がすぐに思いついた解答は一つ。他にも別解があると面白いのですが、どうでしょう? 意外に難しそうな気がする。トライしてみてください。