Trước khi trả lời, trước tiên hãy để tôi nói rằng tôi không nghĩ tốt nhất nên ghi tất cả các bảng vào một bảng duy nhất. Nếu cơ sở dữ liệu của bạn phát triển, bạn có thể kết thúc với sự tranh cãi nghiêm trọng trên bảng Nhật ký. Ngoài ra, tất cả dữ liệu của bạn phải được thay đổi thành varchar hoặc sql_variant để được đặt trong cùng một cột, buộc nó phải chiếm nhiều dung lượng hơn. Tôi cũng nghĩ rằng việc ghi từng cột được cập nhật vào một hàng riêng biệt (bỏ qua các cột không được cập nhật) sẽ làm cho nó rất khó cho bạn để truy vấn. Bạn có biết cách kết hợp tất cả dữ liệu đó lại với nhau để thực sự có được cái nhìn tổng hợp và hợp lý về những thay đổi của từng hàng, khi nào và bởi ai không? Theo tôi, có một bảng nhật ký cho mỗi bảng, sẽ dễ dàng hơn nhiều. Sau đó, bạn sẽ không gặp phải sự cố đang gặp phải khi cố gắng làm cho nó hoạt động.
Ngoài ra, bạn có biết về SQL Server 2008 Thay đổi thu thập dữ liệu ? Thay vào đó, hãy sử dụng nó, nếu bạn đang sử dụng phiên bản Enterprise hoặc Developer của SQL Server!
Ngoài vấn đề đó, bạn có thể làm những gì bạn muốn với UNPIVOT hợp lý (thực hiện phiên bản của riêng bạn). Bạn thực sự không thể sử dụng Native SQL 2005 UNPIVOT vì bạn có hai cột đích chứ không phải một. Đây là một ví dụ cho SQL Server 2005 trở lên bằng cách sử dụng ÁP DỤNG CROSS để thực hiện UNPIVOT:
INSERT INTO dbo.LOG (Id_Table, Table_Key_Value, Id_Value, Old_Value, New_Value)
SELECT 12345, I.Id, X.Id_Value, X.Old_Value, X.New_Value
FROM
INSERTED I
INNER JOIN DELETED D ON I.ID = D.ID
CROSS APPLY (
SELECT 4556645, D.Name, I.Name
UNION ALL SELECT 544589, D.Surname, I.Surname
) X (Id_Value, Old_Value, New_Value)
WHERE
X.Old_Value <> X.New_Value
Đây là một phương pháp chung hơn cho SQL 2000 hoặc các DBMS khác (về mặt lý thuyết sẽ hoạt động trong Oracle, MySQL, v.v. - đối với Oracle, hãy thêm FROM DUAL
cho mỗi CHỌN trong bảng dẫn xuất):
INSERT INTO dbo.LOG (Id_Table, Table_Key_Value, Id_Value, Old_Value, New_Value)
SELECT *
FROM (
SELECT
12345,
I.Id,
X.Id_Value,
CASE X.Id_Value
WHEN 4556645 THEN D.Name
WHEN 544589 THEN D.Surname
END Old_Value,
CASE X.Id_Value
WHEN 4556645 THEN I.Name
WHEN 544589 THEN I.Surname
END New_Value
FROM
INSERTED I
INNER JOIN DELETED D ON I.ID = D.ID
CROSS JOIN (
SELECT 4556645
UNION ALL SELECT 544589
) X (Id_Value)
) Y
WHERE
Y.Old_Value <> Y.New_Value
SQL Server 2005 trở lên có lệnh UNPIVOT gốc, mặc dù nói chung, ngay cả khi UNPIVOT sẽ hoạt động, tôi thích sử dụng CROSS APPLICY thay thế vì có nhiều tính linh hoạt hơn để thực hiện những gì tôi muốn. Cụ thể, lệnh UNPIVOT gốc không hoạt động ở đây vì UNPIVOT chỉ có thể nhắm mục tiêu một cột đích duy nhất, nhưng bạn cần hai (Old_Value, New_Value). Nối hai cột thành một giá trị duy nhất (và tách sau đó) là không tốt; tạo một giá trị tương quan hàng vô nghĩa với PIVOT sau đó là không tốt và tôi không thể nghĩ ra cách khác để làm điều đó mà không phải là một biến thể của hai hàng đó. Giải pháp ÁP DỤNG CHÉO sẽ thực sự là giải pháp tốt nhất cho bạn để phù hợp với cấu trúc bảng nhật ký chính xác mà bạn đã mô tả.
So với các truy vấn của tôi ở đây, phương pháp số 1 của bạn cũng sẽ không hoạt động (theo tỷ lệ khoảng {số cột}:1 hiệu suất kém hơn). Phương pháp số 2 của bạn là một ý tưởng hay nhưng vẫn chưa tối ưu vì việc gọi một UDF có chi phí lớn, cộng với việc bạn phải lặp qua từng hàng (rùng mình).