Zanim odpowiem, pozwól mi najpierw powiedzieć, że nie sądzę, aby logować wszystkie stoły do jednej tabeli. Jeśli twoja baza danych się rozrośnie, możesz skończyć z poważną rywalizacją o tabelę Log. Ponadto wszystkie dane muszą zostać zmienione na varchar lub sql_variant, aby zostały umieszczone w tej samej kolumnie, co zmusza je do zajęcia większej ilości miejsca. Myślę też, że rejestrowanie każdej zaktualizowanej kolumny w osobnym wierszu (pomijanie kolumn, które nie są aktualizowane) sprawi, że będzie bardzo trudne do zapytania. Czy wiesz, jak zebrać wszystkie te dane, aby faktycznie uzyskać złożony i rozsądny widok zmian w każdym wierszu, kiedy i przez kogo? Moim zdaniem posiadanie jednej tabeli logarytmicznej na stół będzie znacznie łatwiejsze. Wtedy nie będziesz mieć problemów, których doświadczasz, próbując je uruchomić.
Czy wiesz również o SQL Server 2008 Zmień przechwytywanie danych ? Użyj tego zamiast, jeśli używasz wersji Enterprise lub Developer SQL Server!
Oprócz tego możesz robić, co chcesz, za pomocą logicznego UNPIVOT (wykonując własną wersję). Nie możesz tak naprawdę użyć UNPIVOT natywnego SQL 2005, ponieważ masz dwie kolumny docelowe, a nie jedną. Oto przykład dla SQL Server 2005 i nowszych przy użyciu CROSS APPLY do wykonania 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
Oto bardziej ogólna metoda dla SQL 2000 lub innych DBMS (teoretycznie powinna działać w Oracle, MySQL itp. -- dla Oracle dodaj FROM DUAL
do każdego SELECT w tabeli pochodnej):
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 i nowsze mają natywne polecenie UNPIVOT, chociaż ogólnie, nawet jeśli UNPIVOT będzie działać, lubię zamiast tego używać CROSS APPLY, ponieważ zapewniam większą elastyczność w robieniu tego, co chcę. W szczególności natywne polecenie UNPIVOT nie działa tutaj, ponieważ UNPIVOT może kierować tylko do jednej kolumny docelowej, ale potrzebujesz dwóch (Stara_Wartość, Nowa_Wartość). Łączenie dwóch kolumn w jedną wartość (i późniejsze rozdzielanie) nie jest dobre; tworzenie bezsensownej wartości korelatora wierszy do PIVOT z później nie jest dobre i nie mogę wymyślić innego sposobu na zrobienie tego, który nie jest odmianą tych dwóch. Rozwiązanie CROSS APPLY będzie naprawdę najlepsze, aby dopasować dokładną strukturę tabeli logów, którą opisałeś.
W porównaniu do moich zapytań tutaj, metoda nr 1 nie będzie działać tak dobrze (w stosunku około {liczba kolumn}:1 gorsza wydajność). Twoja metoda nr 2 jest dobrym pomysłem, ale nadal nieoptymalna, ponieważ wywołanie UDF wiąże się z dużym obciążeniem, a ponadto musisz zapętlić każdy wiersz (drżenie).