SQL Server non tiene traccia delle modifiche specifiche alle tabelle. Se si desidera o si ha bisogno di questo livello di dettaglio, è necessario creare un trigger DDL (introdotto in SQL Server 2005) che possa intercettare determinati eventi specifici o anche classi di eventi e registrare tali modifiche in una tabella della cronologia creata.
DDL I trigger sono trigger "dopo"; non esiste un'opzione "invece di". Tuttavia, se si desidera disabilitare un'azione, è sufficiente emettere un numero ROLLBACK
e questo annullerà l'evento.
La pagina di MSDN per DDL Triggers ha un sacco di buone informazioni riguardo alle modalità di intrappolare o eventi specifici (cioè ALTER TABLE
) e utilizzando la funzione di EVENTDATA
, che restituisce XML, per ottenere le specifiche di quale evento sparato il grilletto, tra cui l'esatto Query SQL che è stata eseguita. Infatti, la pagina MSDN per Use the EVENTDATA Function ha anche semplici esempi di creazione di un trigger DDL per acquisire le istruzioni ALTER TABLE
(nella sezione " ALTER TABLE e ALTER DATABASE Events") e creare un trigger DDL per acquisire gli eventi in una tabella di log (in la sezione "Esempio"). Poiché tutti i comandi ALTER TABLE
generano questo trigger, è necessario analizzare quali sono specifici per ciò che si sta cercando. E, forse ora che sai che questa è un'opzione, è necessario catturare più di una semplice aggiunta di colonne (ad esempio, rilasciare colonne, cambiare il tipo di dati e/o NULLability, ecc.).
Si noti che è possibile creare un trigger DLL ON ALL SERVER
per eventi nell'ambito del database come ALTER_TABLE
.
Se volete vedere la struttura del XML per qualsiasi evento o classe di evento, vai a:
http://schemas.microsoft.com/sqlserver/2006/11/eventdata/
e cliccare sul pulsante "Versione corrente:" collegamento. Se vuoi vedere un evento o una classe di eventi specifici, fai una ricerca (solitamente Control-F nel browser) sul nome dell'evento che verrebbe utilizzato nella clausola "FOR" del trigger (incluso il trattino basso). Quello che segue è lo schema per l'evento ALTER_TABLE
:
<xs:complexType name="EVENT_INSTANCE_ALTER_TABLE">
<xs:sequence>
<!-- Basic Envelope -->
<xs:element name="EventType" type="SSWNAMEType"/>
<xs:element name="PostTime" type="xs:string"/>
<xs:element name="SPID" type="xs:int"/>
<!-- Server Scoped DDL -->
<xs:element name="ServerName" type="PathType"/>
<xs:element name="LoginName" type="SSWNAMEType"/>
<!-- DB Scoped DDL -->
<xs:element name="UserName" type="SSWNAMEType"/>
<!-- Main Body -->
<xs:element name="DatabaseName" type="SSWNAMEType"/>
<xs:element name="SchemaName" type="SSWNAMEType"/>
<xs:element name="ObjectName" type="SSWNAMEType"/>
<xs:element name="ObjectType" type="SSWNAMEType"/>
<xs:element name="Parameters" type="EventTag_Parameters" minOccurs="0"/>
<xs:element name="AlterTableActionList" type="AlterTableActionListType" minOccurs="0"/>
<xs:element name="TSQLCommand" type="EventTag_TSQLCommand"/>
</xs:sequence>
</xs:complexType>
Ecco un semplice test per vedere come funziona e ciò che la risultante EventData XML assomiglia:
IF (EXISTS(
SELECT *
FROM sys.server_triggers sst
WHERE sst.name = N'CaptureAlterTable'
))
BEGIN
DROP TRIGGER CaptureAlterTable ON ALL SERVER;
END;
GO
CREATE TRIGGER CaptureAlterTable
ON ALL SERVER -- capture events for all databases
FOR ALTER_TABLE -- only capture ALTER TABLE events
AS
PRINT CONVERT(NVARCHAR(MAX), EVENTDATA()); -- Display in "Messages" tab in SSMS
GO
Prima creiamo una semplice, tabella reale in tempdb (questi eventi non vengono catturati per le tabelle temporanee):
USE [tempdb];
CREATE TABLE dbo.MyAlterTest (Col2 INT NULL);
Successivamente aggiungiamo una colonna. Facciamo questo da un database diverso per assicurarci che l'XML catturi il database in cui l'oggetto esiste invece il database corrente. Si prega di notare l'involucro delle parole alTeR Table tempDB.dbo.MyALTERTest ... DATEcreated
da confrontare con ciò che è nell'XML.
USE [master];
alTeR Table tempDB.dbo.MyALTERTest ADD DATEcreated DATETIME NOT NULL;
si dovrebbe vedere il seguente nella scheda "Messaggi" (i commenti aggiunti da me):
<EVENT_INSTANCE>
<EventType>ALTER_TABLE</EventType>
<PostTime>2014-12-15T10:53:04.523</PostTime>
<SPID>55</SPID>
<ServerName>_{server_name}_</ServerName>
<LoginName>_{login_name}_</LoginName>
<UserName>dbo</UserName>
<DatabaseName>tempdb</DatabaseName> <!-- casing is based on database definition -->
<SchemaName>dbo</SchemaName>
<ObjectName>MyAlterTest</ObjectName> <!-- casing is based on object definition -->
<ObjectType>TABLE</ObjectType>
<AlterTableActionList>
<Create>
<Columns>
<Name>DATEcreated</Name> <!-- casing is taken from executed query -->
</Columns>
</Create>
</AlterTableActionList>
<TSQLCommand>
<SetOptions ANSI_NULLS="ON" ANSI_NULL_DEFAULT="ON" ANSI_PADDING="ON" QUOTED_IDENTIFIER="ON" ENCRYPTED="FALSE"/>
<CommandText>alTeR Table tempDB.dbo.MyALTERTest ADD DATEcreated DATETIME NOT NULL;
</CommandText>
</TSQLCommand>
</EVENT_INSTANCE>
Sarebbe stato bello se i dettagli per-colonna (ad esempio NULL/NOT NULL, datatype, ecc.) sono stati acquisiti invece del solo nome, ma se necessario, questi possono essere analizzati dall'elemento CommandText
.
Si dovrebbe guardare SYS.OBJECTS unito a SYS.COLUMNS. SYS.OBJECTS ha il campo create_date: http://technet.microsoft.com/en-us/library/ms190324.aspx –