2012-02-24 39 views
12

Sự cố:
Tôi có bảng ghi lại các hàng dữ liệu trong foo. Mỗi lần hàng được cập nhật, một hàng mới được chèn cùng với một số sửa đổi. Bảng trông giống như:Chọn phiên bản mới nhất và cụ thể trong mỗi nhóm hồ sơ, cho nhiều nhóm

id rev field 
1 1 test1 
2 1 fsdfs 
3 1 jfds 
1 2 test2 

Lưu ý rằng trong bảng bản ghi cuối cùng là phiên bản mới hơn của hàng đầu tiên.

Có ai biết cách hiệu quả để truy vấn phiên bản mới nhất của hàng không, ans phiên bản cụ thể của bản ghi? Ví dụ: truy vấn cho rev=2 sẽ trả lại hàng 2, 3 và 4 (không phải là hàng đầu tiên được thay thế) trong khi truy vấn rev=1 mang lại các hàng đó với rev < = 1 và trong trường hợp id trùng lặp, id có phiên bản cao hơn số được chọn (bản ghi: 1, 2, 3).

Tôi không thực sự chắc chắn nếu điều này thậm chí có thể trong SQL Server ...

tôi sẽ không thích trả về kết quả một cách lặp đi lặp lại.

+0

Phiên bản nào của máy chủ sql bạn đang sử dụng? –

+0

MS SQL 2008 R2, nhưng lý tưởng tôi muốn tạo một truy vấn không phụ thuộc vào bất kỳ chi tiết cụ thể nào của máy chủ sql. – orange

+0

Tại sao câu hỏi này được gắn thẻ là 'đệ quy' và 'rcs'? –

Trả lời

28

Để có được chỉ phiên bản mới nhất:

SELECT * from t t1 
WHERE t1.rev = 
    (SELECT max(rev) FROM t t2 WHERE t2.id = t1.id) 

Để có được một phiên bản cụ thể, trong trường hợp này 1 (và nếu một mục không có sửa đổi nhưng các phiên bản nhỏ nhất tiếp theo):

SELECT * from foo t1 
WHERE t1.rev = 
    (SELECT max(rev) 
    FROM foo t2 
    WHERE t2.id = t1.id 
    AND t2.rev <= 1) 

Nó có thể không phải là cách hiệu quả nhất để làm điều này, nhưng ngay bây giờ tôi không thể tìm ra cách tốt hơn để làm điều này.

+0

Cảm ơn bạn đã trả lời. Điều này hoạt động tốt. Tại sao bạn nghĩ rằng nó không hiệu quả? – orange

+1

Vì truy vấn lồng nhau. Về cơ bản cho mỗi hàng trong t bạn phải làm các truy vấn thứ hai. – Tim

+2

@Tim - Không đúng sự thật. SQL là khai báo không bắt buộc. Trong trường hợp này SQL Server biết mẫu này và kế hoạch đơn giản đáng ngạc nhiên. [hình ảnh kế hoạch] (http://i.stack.imgur.com/MUb0m.jpg) –

4

Nếu bạn muốn tất cả các phiên bản mới nhất của từng lĩnh vực, bạn có thể sử dụng

SELECT C.rev, C.fields FROM (
    SELECT MAX(A.rev) AS rev, A.id 
    FROM yourtable A 
    GROUP BY A.id) 
AS B 
INNER JOIN yourtable C 
ON B.id = C.id AND B.rev = C.rev 

Trong trường hợp ví dụ của bạn, điều đó sẽ trở

rev field 
1 fsdfs 
1 jfds 
2 test2 
+0

Không thể tìm thấy cột "A" hoặc hàm do người dùng xác định hoặc tổng hợp "A.MAX" hoặc tên không rõ ràng. Thông báo lỗi này xuất hiện, nhưng nó không giúp tôi quá nhiều ... – orange

+0

bạn không cần A. trước MAX, chỉ cần sử dụng tối đa như thế này: MAX (A.rev) hoặc max (rev) – Tim

+0

Rất tiếc , lỗi của tôi! Đã sửa truy vấn. – Treb

1
SELECT foo.* from foo 
left join foo as later 
on foo.id=later.id and later.rev>foo.rev 
where later.id is null; 
4

Đây là cách tôi sẽ làm đi. ROW_NUMBER() đòi hỏi SQL Server 2005 hay muộn

mẫu dữ liệu:

DECLARE @foo TABLE (
    id int, 
    rev int, 
    field nvarchar(10) 
) 

INSERT @foo VALUES 
    (1, 1, 'test1'), 
    (2, 1, 'fdsfs'), 
    (3, 1, 'jfds'), 
    (1, 2, 'test2') 

Truy vấn:

DECLARE @desiredRev int 

SET @desiredRev = 2 

SELECT * FROM (
SELECT 
    id, 
    rev, 
    field, 
    ROW_NUMBER() OVER (PARTITION BY id ORDER BY rev DESC) rn 
FROM @foo WHERE rev <= @desiredRev 
) numbered 
WHERE rn = 1 

Các nội SELECT trả về tất cả các hồ sơ có liên quan, và trong mỗi nhóm id (đó là PARTITION BY), tính số hàng khi được sắp xếp theo thứ tự giảm dần rev.

Bên ngoài SELECT chỉ chọn thành viên đầu tiên (vì vậy, thành viên có số lượng cao nhất rev) từ mỗi nhóm id.

Output khi @desiredRev = 2:

id   rev   field  rn 
----------- ----------- ---------- -------------------- 
1   2   test2  1 
2   1   fdsfs  1 
3   1   jfds  1 

Output khi @desiredRev = 1:

id   rev   field  rn 
----------- ----------- ---------- -------------------- 
1   1   test1  1 
2   1   fdsfs  1 
3   1   jfds  1 
+0

Dường như hoạt động tốt. Tôi thích rằng bạn có thể chọn số sửa đổi dễ dàng. Tuy nhiên, tôi thích một truy vấn SQL đơn giản nếu có thể. – orange

2
SELECT 
    MaxRevs.id, 
    revision.field 
FROM 
    (SELECT 
    id, 
    MAX(rev) AS MaxRev 
    FROM revision 
    GROUP BY id 
) MaxRevs 
    INNER JOIN revision 
    ON MaxRevs.id = revision.id AND MaxRevs.MaxRev = revision.rev 
+0

Để cũng chọn một phiên bản cụ thể:. CHỌN sửa đổi * TỪ (SELECT id, MAX (rev) AS MaxRev TỪ sửa đổi ĐÂU rev <= 2 GROUP BY id ) MaxRevs INNER JOIN sửa đổi ON MaxRevs.id = revision.id AND MaxRevs.MaxRev = revision.rev – Mahe

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