Sql 在填充值时合并两个版本跟踪表

Sql 在填充值时合并两个版本跟踪表,sql,postgresql,Sql,Postgresql,我有两个历史记录表跟踪数据库值中的更改,使用修订id跟踪单个更改。e、 g 表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 目标是将两个表合并为: rev

我有两个历史记录表跟踪数据库值中的更改,使用修订id跟踪单个更改。e、 g

表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
目标是将两个表合并为:

 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 问题是:

  • 这种类型的联接有名称吗
  • 在SQL中执行这种类型的连接是否有一种习惯用法,或者以编程的方式进行比较好(这肯定会更简单、更高效)

这可以通过子查询实现

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

没有特定的联接类型来处理这种查询。您必须以复杂查询或编程方式来完成。下面是针对这个问题的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';
CREATE或REPLACE函数getRev(OUT rev INT,OUT A INT,OUT B CHAR,OUT C INT,OUT D BOOL)将记录集稳定地返回为
$BODY$
声明
c1滚动光标,用于按版次从表1中选择*;
c2滚动光标,用于按版次从表2中选择*;
r1表1%行类型;
r1c表1%行类型;
r2表2%行类型;
r2c表2%行类型;
开始
开c1;
开放c2;
将c1取入r1;
将c2放入r2;
r1c:=r1;
r2c:=r2;
而r1不为空,r2不为空
环
案例
当r1.rev=r2.rev时,则
rev:=r1.rev;
A:=r1.A;
B:=r1.B;
C:=r2.C;
D:=r2.D;
将c1取入r1c;
将c2送入r2c;
案例
当r1c.rev=r2c.rev时,则
r1:=r1c;
r2:=r2c;
当r1c.rev
这应该是O(长度(表1)+长度(表2))

请注意“r1.rev=r2.rev时的情况”中的棘手部分:我们必须选择在哪个表上继续扫描以进行下一次迭代。正确的版本是在光标后具有最小版本值的版本,以通过两个表中可用的所有版本号。你可以通过在C或C++中编码来获得更好的性能。p>


什么是RDBMS?有些数据库支持这些类型的操作,因此(特别是在数据空间很大的情况下)这实际上可能在数据库中更有效。因此,您不需要查询,只需要这两个问题的答案?数据库是PostgreSQL,尽管从技术上讲,这项工作应该独立于数据库(实际上这不会发生)。是的,只是对问题的答案感兴趣,除非我忽略了一个更简单的查询。
isnull
不是有效的postgresql语法
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