2012-10-19 9 views
8

私は、リビジョンIDを使用して個々の変更を追跡するデータベース値の変更を追跡する2つの履歴テーブルを持っています。例えば値を入力中に2つのバージョントラッキングテーブルをマージする

表1:

rev | A | B 
================= 
1 | 100 | 'A' 
4 | 150 | 'A' 
7 | 100 | 'Z' 

表2:

rev | C | D 
================== 
1 | 200 | True 
5 | 0 | True 
8 | 0 | False 

目標はに2つのテーブルをマージすることであろう。

rev | A | B | C | D 
=============================== 
1 | 100 | 'A' | 200 | True 
4 | 150 | 'A' | 200 | True 
5 | 150 | 'A' | 0 | True 
7 | 100 | 'Z' | 0 | True 
8 | 100 | 'Z' | 0 | False 

所与のためのそれであるという考えをそのリビジョンに対応する値、またはそれよりも小さいリビジョンを取ることにしました。

頭に浮かぶSQLクエリは、それぞれのREV1 = MAX(REV1)はREV2を与えられたサブクエリを使用して行を選択し、制約のrev1 rev2の <で2つのテーブルを結合交差に似ものになるだろう;このクエリをその相手と交換することで結合するrev2およびrev1;最後に、rev1 = rev2から重複を除外します。

質問は以下のとおりです。

  • 参加のこのタイプの名前はありますか?
  • SQLでこのタイプの結合を実行するためのイディオムがありますか、それともプログラマチックに行う方が良いでしょうか(これは間違いなくより簡単で効率的です)。
+0

?これらのタイプの操作がサポートされているものもあります(特に、データスペースが大きい場合は、実際にはデータベースで効率的です)。 –

+0

質問はしたくないのですが、その2つの質問に対する答えだけです。 –

+0

データベースはPostgreSQLですが、技術的にはDBとは独立しているはずです(現実的にはこれは起こりません)。そして、私が見落としているクエリがはるかに単純でない限り、質問に対する答えに興味があります。 –

答えて

2

SQL Fiddle

select 
    coalesce(t1.rev, t2.rev) rev, 
    coalesce(a, lag(a, 1) over(order by coalesce(t2.rev, t1.rev))) a, 
    coalesce(b, lag(b, 1) over(order by coalesce(t2.rev, t1.rev))) b, 
    coalesce(c, lag(c, 1) over(order by coalesce(t1.rev, t2.rev))) c, 
    coalesce(d, lag(d, 1) over(order by coalesce(t1.rev, t2.rev))) d 
from 
    t1 
    full join 
    t2 on t1.rev = t2.rev 
order by rev 
何RDBMS
1

これは、サブによって達成することができるには、特定のはありません

SELECT ISNULL(Table1.rev,Table2.rev) AS rev 
,ISNULL(A,(SELECT TOP 1 A FROM Table1 AS T1 WHERE ISNULL(Table1.rev,Table2.rev) > T1.rev AND A IS NOT NULL ORDER BY rev DESC)) AS A 
,ISNULL(B,(SELECT TOP 1 B FROM Table1 AS T1 WHERE ISNULL(Table1.rev,Table2.rev) > T1.rev AND B IS NOT NULL ORDER BY rev DESC)) AS B 
,ISNULL(C,(SELECT TOP 1 C FROM Table2 AS T2 WHERE ISNULL(Table1.rev,Table2.rev) > T2.rev AND C IS NOT NULL ORDER BY rev DESC)) AS C 
,ISNULL(D,(SELECT TOP 1 D FROM Table2 AS T2 WHERE ISNULL(Table1.rev,Table2.rev) > T2.rev AND D IS NOT NULL ORDER BY rev DESC)) AS D 
FROM Table1 
FULL OUTER JOIN Table2 
ON Table1.rev = Table2.rev 
+0

'isnull'は有効なpostgresql構文ではありません –

0

は、クエリの並べ替えを処理するために結合タイプを照会します。複雑なクエリとしてもプログラムでも行う必要があります。以下は、この問題のPL/PGSQLコードのサンプルデータを使用した例です。

CREATE OR REPLACE FUNCTION getRev(OUT rev INT, OUT A INT, OUT B CHAR, OUT C INT, OUT D BOOL) RETURNS SETOF record STABLE AS 
$BODY$ 
DECLARE 
    c1 SCROLL CURSOR FOR SELECT * FROM Table1 ORDER BY rev; 
    c2 SCROLL CURSOR FOR SELECT * FROM Table2 ORDER BY rev; 
    r1 Table1%ROWTYPE; 
    r1c Table1%ROWTYPE; 
    r2 Table2%ROWTYPE; 
    r2c Table2%ROWTYPE; 
BEGIN 
    OPEN c1; 
    OPEN c2; 
    FETCH c1 INTO r1; 
    FETCH c2 INTO r2; 
    r1c := r1; 
    r2c := r2; 
    WHILE r1 IS NOT NULL AND r2 IS NOT NULL 
    LOOP 
    CASE 
    WHEN r1.rev = r2.rev THEN 
     rev := r1.rev; 
     A := r1.a; 
     B := r1.b; 
     C := r2.c; 
     D := r2.d; 
     FETCH c1 INTO r1c; 
     FETCH c2 INTO r2c; 
     CASE 
     WHEN r1c.rev = r2c.rev THEN 
     r1 := r1c; 
     r2 := r2c; 
     WHEN r1c.rev < r2c.rev THEN 
      r1 := r1c; 
     FETCH PRIOR FROM c2 INTO r2c; 
    ELSE 
      r2 := r2c; 
     FETCH PRIOR FROM c1 INTO r1c; 
     END CASE; 
    WHEN r1.rev < r2.rev THEN 
     WHILE r1c IS NOT NULL AND r1c.rev < r2.rev LOOP 
     r1 := r1c; 
     FETCH c1 INTO r1c; 
     END LOOP; 
     rev := r2.rev; 
     A := r1.a; 
     B := r1.b; 
     C := r2.c; 
     D := r2.d; 
     r1 := r1c; 
    ELSE 
     WHILE r2c IS NOT NULL AND r2c.rev < r1.rev LOOP 
     r2 := r2c; 
     FETCH c2 INTO r2c; 
     END LOOP; 
     rev := r1.rev; 
     A := r1.a; 
     B := r1.b; 
     C := r2.c; 
     D := r2.d; 
     r2 := r2c; 
    END CASE; 
    RETURN NEXT; 
    END LOOP; 
    CLOSE c1; 
    CLOSE c2; 
    RETURN; 
END 
$BODY$ 
LANGUAGE 'plpgsql'; 

これはOで実行すべきである(長さ(表1)+長さ(表2))。

「CASE WHEN r1.rev = r2.rev」のトリッキーな部分に注意してください。次の反復のスキャンを続ける表を選択する必要があります。正しいものは、カーソルの後に最小のrev値を持つもので、両方のテーブルで利用可能なすべてのレビ数値を取得します。あなたは確かにCやC++でそれをコーディングしてより良いパフォーマンスを得ることができます。

関連する問題