Tôi có một bảng trong máy chủ SQL trông như thế này:
Id |Version |Name |date |fieldA |fieldB ..|fieldZ
1 |1 |Foo |20120101|23 | ..|25334123
2 |2 |Foo |20120101|23 |NULL ..|NULL
3 |2 |Bar |20120303|24 |123......|NULL
4 |2 |Bee |20120303|34 |-34......|NULL
Tôi đang làm việc trên một thủ tục được lưu trữ để tìm khác biệt, lấy dữ liệu đầu vào và số phiên bản. Dữ liệu đầu vào có các cột từ Trường tăng tênZ. Hầu hết các cột trường được dự kiến là NULL, tức là, mỗi hàng thường chỉ có dữ liệu cho một vài trường đầu tiên, phần còn lại là NULL. Tên, ngày và phiên bản tạo thành một ràng buộc duy nhất trên bảng.
Tôi cần phải phân biệt dữ liệu được nhập vào bảng này cho một phiên bản nhất định. Mỗi hàng cần phải được phân biệt - một hàng được xác định theo tên, ngày và phiên bản và bất kỳ thay đổi nào trong bất kỳ giá trị nào trong các cột trường sẽ cần hiển thị trong khác.
Cập nhật: tất cả các trường không cần phải là kiểu thập phân. Một số trong số họ có thể là nvarchar. Tôi thích sự khác biệt xảy ra mà không cần chuyển đổi loại, mặc dù đầu ra diff có thể chuyển đổi mọi thứ thành nvarchar vì nó chỉ được sử dụng để hiển thị có mục đích.
Giả sử đầu vào là như sau và phiên bản được yêu cầu là 2 ,:
Name |date |fieldA |fieldB|..|fieldZ
Foo |20120101|25 |NULL |.. |NULL
Foo |20120102|26 |27 |.. |NULL
Bar |20120303|24 |126 |.. |NULL
Baz |20120101|15 |NULL |.. |NULL
Khác biệt cần phải ở định dạng sau:
name |date |field |oldValue |newValue
Foo |20120101|FieldA |23 |25
Foo |20120102|FieldA |NULL |26
Foo |20120102|FieldB |NULL |27
Bar |20120303|FieldB |123 |126
Baz |20120101|FieldA |NULL |15
Giải pháp của tôi cho đến nay là trước tiên tạo ra một diff, sử dụng EXCEPT và UNION. Sau đó chuyển đổi diff sang định dạng đầu ra mong muốn bằng ỨNG DỤNG THAM GIA và CROSS. Mặc dù điều này dường như đang hoạt động, tôi tự hỏi liệu có một cách sạch hơn và hiệu quả hơn để làm điều này. Số lượng các trường gần bằng 100 và mỗi vị trí trong mã có ... thực sự là một số lượng lớn các dòng. Cả bảng đầu vào và bảng hiện có dự kiến sẽ khá lớn theo thời gian. Tôi chưa quen với SQL và vẫn đang cố gắng học điều chỉnh hiệu năng.
Đây là SQL cho nó:
CREATE TABLE #diff
( [change] [nvarchar](50) NOT NULL,
[name] [nvarchar](50) NOT NULL,
[date] [int] NOT NULL,
[FieldA] [decimal](38, 10) NULL,
[FieldB] [decimal](38, 10) NULL,
.....
[FieldZ] [decimal](38, 10) NULL
)
--Generate the diff in a temporary table
INSERT INTO #diff
SELECT * FROM
(
(
SELECT
'old' as change,
name,
date,
FieldA,
FieldB,
...,
FieldZ
FROM
myTable mt
WHERE
version = @version
AND mt.name + '_' + CAST(mt.date AS VARCHAR) IN (SELECT name + '_' + CAST(date AS VARCHAR) FROM @diffInput)
EXCEPT
SELECT 'old' as change,* FROM @diffInput
)
UNION
(
SELECT 'new' as change, * FROM @diffInput
EXCEPT
SELECT
'new' as change,
name,
date,
FieldA,
FieldB,
...,
FieldZ
FROM
myTable mt
WHERE
version = @version
AND mt.name + '_' + CAST(mt.date AS VARCHAR) IN (SELECT name + '_' + CAST(date AS VARCHAR) FROM @diffInput)
)
) AS myDiff
SELECT
d3.name, d3.date, CrossApplied.field, CrossApplied.oldValue, CrossApplied.newValue
FROM
(
SELECT
d2.name, d2.date,
d1.FieldA AS oldFieldA, d2.FieldA AS newFieldA,
d1.FieldB AS oldFieldB, d2.FieldB AS newFieldB,
...
d1.FieldZ AS oldFieldZ, d2.FieldZ AS newFieldZ,
FROM #diff AS d1
RIGHT OUTER JOIN #diff AS d2
ON
d1.name = d2.name
AND d1.date = d2.date
AND d1.change = 'old'
WHERE d2.change = 'new'
) AS d3
CROSS APPLY (VALUES ('FieldA', oldFieldA, newFieldA),
('FieldB', oldFieldB, newFieldB),
...
('FieldZ', oldFieldZ, newFieldZ))
CrossApplied (field, oldValue, newValue)
WHERE
crossApplied.oldValue != crossApplied.newValue
OR (crossApplied.oldValue IS NULL AND crossApplied.newValue IS NOT NULL)
OR (crossApplied.oldValue IS NOT NULL AND crossApplied.newValue IS NULL)
Cảm ơn bạn!