2012-10-19 40 views
8

Tôi có hai bảng lịch sử theo dõi các thay đổi trong giá trị cơ sở dữ liệu, sử dụng id sửa đổi để theo dõi các thay đổi riêng lẻ. ví dụ.Hợp nhất hai bảng theo dõi phiên bản trong khi điền các giá trị

Bảng 1:

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

Bảng 2:

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

Mục tiêu sẽ được sáp nhập hai bảng vào:

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 

Ý tưởng được rằng cho cho một định sửa đổi, tôi sẽ lấy các giá trị tương ứng với bản sửa đổi đó hoặc bản sửa đổi cao nhất ít hơn.

Truy vấn SQL mà nói đến cái tâm sẽ là một cái gì đó giống như qua tham gia hai bảng với chế REV1 < rev2, sau đó chọn hàng sử dụng một subquery nơi REV1 = max (REV1) cho từng đưa rev2 ; kết hợp truy vấn này với đối tác của nó trao đổi rev2rev1; và cuối cùng lọc ra các bản sao từ nơi rev1 = rev2.

Các câu hỏi là:

  • Có một tên cho loại tham gia?
  • Có thành ngữ nào để thực hiện kiểu tham gia này trong SQL hay tốt hơn nếu thực hiện theo chương trình (điều này chắc chắn sẽ đơn giản hơn nhiều và có thể hiệu quả hơn)?
+0

RDBMS gì? Một số có hỗ trợ cho các loại hoạt động, vì vậy (đặc biệt là nếu không gian dữ liệu lớn) điều này thực sự có thể hiệu quả hơn trong cơ sở dữ liệu. –

+0

Vì vậy, bạn không muốn truy vấn mà chỉ là câu trả lời cho hai câu hỏi đó? –

+0

Cơ sở dữ liệu là PostgreSQL, mặc dù về mặt kỹ thuật, công việc được cho là độc lập với DB (thực tế điều này sẽ không xảy ra). Và vâng, chỉ cần quan tâm đến câu trả lời cho các câu hỏi, trừ khi có một truy vấn đơn giản hơn nhiều mà tôi đang xem. –

Trả lời

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 
1

Điều này có thể đạt được bằng cách phụ truy vấn

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' không phải là cú pháp postgresql hợp lệ –

0

Không cụ thể tham gia loại để xử lý mà loại truy vấn. Bạn phải làm điều đó như một truy vấn phức tạp hoặc theo lập trình. Dưới đây là ví dụ về mã PL/PGSQL cho vấn đề này, sử dụng dữ liệu ví dụ của bạn.

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'; 

Điều này sẽ chạy trong O (chiều dài (Bảng1) + chiều dài (Bảng2)).

Lưu ý phần phức tạp trong "TRƯỜNG HỢP KHI r1.rev = r2.rev": chúng tôi phải chọn bảng mà chúng tôi tiếp tục quét cho lần lặp tiếp theo. Giá trị chính xác là giá trị có giá trị vòng quay nhỏ nhất sau con trỏ, để có được tất cả các số rev có sẵn trong cả hai bảng. Bạn chắc chắn có thể có được hiệu suất tốt hơn bằng cách mã hóa nó trong C hoặc C++.

Các vấn đề liên quan