Voordat ik antwoord, wil ik eerst zeggen dat ik denk dat het niet het beste is om alle tabellen in een enkele tabel te loggen. Als uw database groeit, kunt u ernstige ruzie krijgen over de Log-tabel. Bovendien moeten al uw gegevens worden gewijzigd in varchar of sql_variant om in dezelfde kolom te worden geplaatst, waardoor deze meer ruimte in beslag neemt. Ik denk ook dat het erg wordt door elke bijgewerkte kolom in een aparte rij te loggen (kolommen die niet zijn bijgewerkt overslaan) moeilijk voor u om te vragen. Weet u hoe u al die gegevens moet samenbrengen om een samengesteld en verstandig beeld te krijgen van de wijzigingen van elke rij, wanneer en door wie? Het hebben van één logtafel per tafel is naar mijn mening veel gemakkelijker. Dan heb je niet de problemen die je ervaart om het te laten werken.
Wist u ook over SQL Server 2008 Gegevens vastleggen wijzigen ? Gebruik dat in plaats daarvan, als u de Enterprise- of Developer-edities van SQL Server gebruikt!
Afgezien van dat probleem, kun je doen wat je wilt met een logische UNPIVOT (je eigen versie ervan uitvoeren). U kunt de Native SQL 2005 UNPIVOT niet echt gebruiken omdat u twee doelkolommen heeft, niet één. Hier is een voorbeeld voor SQL Server 2005 en hoger waarbij CROSS APPLY wordt gebruikt om de UNPIVOT uit te voeren:
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
Hier is een meer generieke methode voor SQL 2000 of andere DBMS-en (zou theoretisch moeten werken in Oracle, MySQL, enz. -- voor Oracle voeg FROM DUAL
toe aan elke SELECT in de afgeleide tabel):
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 en hoger hebben de oorspronkelijke opdracht UNPIVOT, hoewel ik in het algemeen, zelfs als UNPIVOT zal werken, in plaats daarvan graag CROSS APPLY gebruik omdat er meer flexibiliteit is om te doen wat ik wil. In het bijzonder is de oorspronkelijke opdracht UNPIVOT hier niet werkbaar omdat UNPIVOT zich slechts op één bestemmingskolom kan richten, maar u hebt er twee nodig (Old_Value, New_Value). Het samenvoegen van de twee kolommen tot een enkele waarde (en later scheiden) is niet goed; het creëren van een betekenisloze rijcorrelatorwaarde voor PIVOT met achteraf is niet goed, en ik kan geen andere manier bedenken om het te doen die geen variatie op die twee is. De CROSS APPLY-oplossing is echt de beste voor u om te passen bij de exacte logtabelstructuur die u hebt beschreven.
Vergeleken met mijn vragen hier, zal uw methode #1 niet zo goed presteren (in een verhouding van ongeveer {het aantal kolommen}:1 slechtere prestaties). Uw methode #2 is een goed idee, maar nog steeds suboptimaal omdat het aanroepen van een UDF een grote overhead met zich meebrengt, en dan moet u elke rij doorlopen (huivering).