SQL Server no realiza un seguimiento de los cambios específicos en las tablas. Si desea o necesita este nivel de detalle, debe crear un desencadenador DDL (introducido en SQL Server 2005) que pueda atrapar ciertos eventos específicos o incluso clases de eventos, y registrar esos cambios en una tabla de historial que cree.
Los activadores DDL son desencadenantes "después"; no hay una opción "en lugar de". Sin embargo, si no desea permitir una acción, puede emitir un ROLLBACK
y eso cancelará lo sucedido.
La página de MSDN para DDL Triggers tiene un montón de buena información sobre cómo atrapar ya sea eventos específicos (es decir ALTER TABLE
) y utilizar la función EVENTDATA
, que devuelve XML, para obtener los detalles de lo evento disparado el gatillo, incluyendo la exacta Consulta SQL que se ejecutó. De hecho, la página de MSDN para Use the EVENTDATA Function incluso tiene ejemplos simples de crear un desencadenador DDL para capturar declaraciones ALTER TABLE
(en la sección "ALTER TABLE y ALTER DATABASE Events") y crear un desencadenador DDL para capturar los eventos en una tabla de registro (en la sección "Ejemplo"). Como todos los comandos ALTER TABLE
dispararán este desencadenador, debe analizar cuáles son específicos de lo que está buscando. Y, tal vez ahora que sabe que esta es una opción, se desea capturar algo más que simplemente agregar columnas (es decir, eliminar columnas, cambiar el tipo de datos y/o NULLability, etc.).
Debe tenerse en cuenta que puede crear un desencadenador DLL ON ALL SERVER
para eventos con base en la base de datos como ALTER_TABLE
.
Si quieres ver la estructura del XML para cualquier evento o clase de evento, ir a:
http://schemas.microsoft.com/sqlserver/2006/11/eventdata/
y hacer clic en la "versión actual:" enlace. Si desea ver un evento o clase de evento específico, simplemente haga una búsqueda (generalmente Control-F en el navegador) en el nombre del evento que se usaría en la cláusula "FOR" del desencadenador (incluido el guión bajo). El siguiente es el esquema para el 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>
Aquí es una prueba muy simple para ver cómo funciona esto y lo que el XML EventData resultante se parece a:
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
Primero creamos un simple, tabla real en tempdb (estos eventos no se capturan para tablas temporales):
USE [tempdb];
CREATE TABLE dbo.MyAlterTest (Col2 INT NULL);
A continuación, agregamos una columna. Hacemos esto desde una base de datos diferente para asegurarnos de que el XML capture la base de datos donde existe el objeto en lugar de la base de datos actual. Tenga en cuenta la carcasa de las palabras alTeR Table tempDB.dbo.MyALTERTest ... DATEcreated
para comparar con lo que está en el XML.
USE [master];
alTeR Table tempDB.dbo.MyALTERTest ADD DATEcreated DATETIME NOT NULL;
debería ver lo siguiente en la pestaña "Mensajes" (comentarios agregados por mí):
<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>
Hubiera sido agradable si los datos por columnas (es decir NULL/NOT NULL, tipo de datos, etc.) se capturaron en lugar de solo el nombre, pero si es necesario, se pueden analizar a partir del elemento CommandText
.
Tendría que mirar SYS.OBJECTS unidos a SYS.COLUMNS. SYS.OBJECTS tiene el campo create_date: http://technet.microsoft.com/en-us/library/ms190324.aspx –