sql >> Database >  >> RDS >> Sqlserver

Updatebewerking loggen in triggers

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).




  1. Groepeer kolommen in meerdere rijen en Group_concate zoals MySQL in SQL Server

  2. Tijdsverschil tussen per persoon tussen opeenvolgende rijen

  3. Hoe MySQL en MSSQL samen gebruiken in de Grails-gegevensbron?

  4. selectbox met meerdere kolommen uit de mysql-database