Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/django/19.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
oc检查表并输出一个字符串,该字符串是正确的CREATETRIGGER语句。。。喜欢代码自动生成。我更喜欢动态sql而不是代码生成。是否也可以检查“错误”更新?像更新t1 set c1=c1-不应该跟踪这些内容…您使用的是什么版本的SQL Server?自_Sql_Sql Server_Triggers_Sql Server 2012 - Fatal编程技术网

oc检查表并输出一个字符串,该字符串是正确的CREATETRIGGER语句。。。喜欢代码自动生成。我更喜欢动态sql而不是代码生成。是否也可以检查“错误”更新?像更新t1 set c1=c1-不应该跟踪这些内容…您使用的是什么版本的SQL Server?自

oc检查表并输出一个字符串,该字符串是正确的CREATETRIGGER语句。。。喜欢代码自动生成。我更喜欢动态sql而不是代码生成。是否也可以检查“错误”更新?像更新t1 set c1=c1-不应该跟踪这些内容…您使用的是什么版本的SQL Server?自,sql,sql-server,triggers,sql-server-2012,Sql,Sql Server,Triggers,Sql Server 2012,oc检查表并输出一个字符串,该字符串是正确的CREATETRIGGER语句。。。喜欢代码自动生成。我更喜欢动态sql而不是代码生成。是否也可以检查“错误”更新?像更新t1 set c1=c1-不应该跟踪这些内容…您使用的是什么版本的SQL Server?自SQL 2008以来,我们已经进行了更改数据捕获。此外,在SQL 2016中,我们得到了时态表。这将起作用,但我正在寻找一种更通用的解决方案,在这种解决方案中,我不需要为每个表指定每个触发器中的每一列。我希望有一个更具活力和可恢复性的解决方案。


oc检查表并输出一个字符串,该字符串是正确的CREATETRIGGER语句。。。喜欢代码自动生成。我更喜欢动态sql而不是代码生成。是否也可以检查“错误”更新?像更新t1 set c1=c1-不应该跟踪这些内容…您使用的是什么版本的SQL Server?自SQL 2008以来,我们已经进行了更改数据捕获。此外,在SQL 2016中,我们得到了时态表。这将起作用,但我正在寻找一种更通用的解决方案,在这种解决方案中,我不需要为每个表指定每个触发器中的每一列。我希望有一个更具活力和可恢复性的解决方案。对于交叉应用,仍然+1。@Jaster,关系数据库被设计为具有稳定的模式,其中列是预先知道的,并且不会经常更改。快速搜索“sp_executesql in trigger”会告诉您,不能在引用
插入的
删除的
表的触发器中运行动态SQL。动态SQL在不同的单独上下文中执行。人们建议将插入的
表复制到某个临时表中,并在动态SQL中引用该临时表。我不确定它是否会工作,您仍然需要以某种方式为temp表定义列。我将仔细查看
更改数据捕获
功能。看起来需要sql Generarator。。。但是你为什么要把身份证给nvarchar?(该列不需要跟踪)@Jaster,你是对的,包含
ID
列没有多大意义,因为它不应该更改。同时,我没有包括
Version
列,因为它总是变化,并且它的实际值通常没有有用的(历史)意义。我希望查询的总体轮廓能够清楚地说明如何根据需要添加更多的列。我正在寻找一种更通用的解决方案,可以应用于多个表,而无需指定每一列+1进行正确的空检查并理解版本列。我只能考虑SQLCLR触发器,它可以动态地构建和执行SQL。根据vladimirs的回答,我猜这就是我的方向。。。只需要对所需的转换有更多的了解。@Jaster,将生成DML触发器代码的动态SQL代码放在。因此,您将保证记录数据更改的主DML触发器始终与表模式同步。但是,我不知道是否可以
更改
在DDL触发器中删除/创建
DML触发器。是否可以修改cdc过程中写入的数据。e、 更改用户/时间?您的意思是更改cdc表吗?是的,您可以更改CDC数据。CDC扫描程序读取事务日志并填充CDC表。然后,您可以对这些表执行任何DML命令,但在读取CDC表并填充history tablesSmart解决方案时不需要它,但我不需要动态脚本来生成触发器。我的问题是关于作为触发器一部分的动态sql,这似乎不是一个选项。
CREATE TABLE [dbo].[History](
    [Id] [uniqueidentifier] NOT NULL CONSTRAINT [DF_History_Id]  DEFAULT (newsequentialid()),
    [ObjectId] [uniqueidentifier] NOT NULL,
    [Timestamp] [datetime] NOT NULL CONSTRAINT [DF_History_Timestamp]  DEFAULT (getdate()),
    [ChangingUser] [varchar](max) NOT NULL CONSTRAINT [DF_History_ChangingUser]  DEFAULT (suser_sname()),
    [Column] [varchar](max) NOT NULL,
    [OldValue] [nvarchar](max) NULL,
    [NewValue] [nvarchar](max) NULL,
 CONSTRAINT [PK_History] PRIMARY KEY CLUSTERED 
(
    [Id] ASC
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]
) ON [PRIMARY] TEXTIMAGE_ON [PRIMARY]
CREATE TRIGGER [dbo].[T1_TraceUpdate]
   on [dbo].[T1]
   AFTER update
AS 
BEGIN
set nocount on;
-- pseudo insert!
insert into History select * from inserted;
END
CREATE TABLE [dbo].[T1](
    [Id] [uniqueidentifier] NOT NULL CONSTRAINT [DF_T1_Id]  DEFAULT (newsequentialid()),
    [Title] [text] NULL,
    [Amount] [int] NULL,
    [Price] [decimal](18, 7) NULL,
    [Version] [timestamp] NOT NULL,
 CONSTRAINT [PK_T1] PRIMARY KEY CLUSTERED 
(
    [Id] ASC
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]
) ON [PRIMARY] TEXTIMAGE_ON [PRIMARY]
1d118497-bf69-e611-9e7d-40a8f04d1095    Abc            3    37,2500000  
9cf095a8-bf69-e611-9e7d-40a8f04d1095    NULL           1    27,3000000  
cc38386d-fe69-e611-9e7d-40a8f04d1095    Storm Catcher  10   NULL    
update T1 set price = isnull(Price,100)*0.7 where Amount > 2
4848D80B-4E73-E611-BD43-40A8F04D1095    1D118497-BF69-E611-9E7D-40A8F04D1095    2016-09-05 11:49:33.473 sa  Price   37,2500000  26.0750000
E80EAB18-4E73-E611-BD43-40A8F04D1095    CC38386D-FE69-E611-9E7D-40A8F04D1095    2016-09-05 11:49:33.473 sa  Price   NULL        70
CREATE TRIGGER [dbo].[T1_TraceUpdate]
    on [dbo].[T1]
    AFTER update
AS 
BEGIN
    set nocount on;

    WITH
    CTE_Inserted
    AS
    (
        SELECT ID, ColumnName, ColumnValue
        FROM
            inserted
            CROSS APPLY
            (VALUES
                ('Title', Title),
                ('Amount', CAST(Amount AS nvarchar(max))),
                ('Price', CAST(Price AS nvarchar(max)))
            ) AS V(ColumnName, ColumnValue)
    )
    ,CTE_Deleted
    AS
    (
        SELECT ID, ColumnName, ColumnValue
        FROM
            deleted
            CROSS APPLY
            (VALUES
                ('Title', Title),
                ('Amount', CAST(Amount AS nvarchar(max))),
                ('Price', CAST(Price AS nvarchar(max)))
            ) AS V(ColumnName, ColumnValue)
    )
    INSERT INTO dbo.History([ObjectId], [Column], [OldValue], [NewValue])
    SELECT
        CTE_Inserted.Id AS [ObjectId]
        ,CTE_Inserted.ColumnName
        ,CTE_Deleted.ColumnValue AS [OldValue]
        ,CTE_Inserted.ColumnValue AS [NewValue]
    FROM
        CTE_Inserted
        INNER JOIN CTE_Deleted
            ON  CTE_Deleted.Id = CTE_Inserted.Id
            AND CTE_Deleted.ColumnName = CTE_Inserted.ColumnName
    WHERE
        ISNULL(CTE_Inserted.ColumnValue, N'') <> ISNULL(CTE_Deleted.ColumnValue, N'')
        OR (CTE_Inserted.ColumnValue IS NULL AND CTE_Deleted.ColumnValue IS NOT NULL) 
        OR (CTE_Inserted.ColumnValue IS NOT NULL AND CTE_Deleted.ColumnValue IS NULL) 
    ;

END
CREATE TRIGGER [dbo].[T1_TraceUpdate]
    on [dbo].[T1]
    AFTER update
AS 
BEGIN
    set nocount on;
    -- Changing Id breaks the logic of the trigger
    IF UPDATE(ID) 
    BEGIN 
        RAISERROR ('ID cannot change.', 16, 1);
        --
    END     
    INSERT INTO dbo.History(ObjectId, [Column], OldValue, NewValue)
    SELECT inserted.ID, ColumnName, OldValue, NewValue
    FROM inserted 
    INNER JOIN Deleted ON  Deleted.Id = Inserted.Id
    CROSS APPLY
       (SELECT ColumnName='Title', OldValue=deleted.Title, NewValue=inserted.Title 
          WHERE isnull(nullif(inserted.Title,deleted.Title), nullif(deleted.Title,inserted.Title)) IS NOT NULL 
        UNION ALL
        SELECT 'Amount', CAST(deleted.Amount AS nvarchar(max)), CAST(inserted.Amount AS nvarchar(max))
          WHERE isnull(nullif(inserted.Amount,deleted.Amount), nullif(deleted.Amount,inserted.Amount)) IS NOT NULL  
        UNION ALL
        SELECT 'Price', CAST(deleted.Price AS nvarchar(max)), CAST(inserted.Price AS nvarchar(max))
          WHERE isnull(nullif(inserted.Price, deleted.Price), nullif(deleted.Price,inserted.Price)) IS NOT NULL
        UNION ALL
        -- you may want to skip version (`timestamp` type) as it's always updated by server
        SELECT 'Version', CONVERT(varchar(max),CONVERT(VARBINARY,deleted.Version),1), CONVERT(varchar(max),CONVERT(VARBINARY,inserted.Version),1)
          WHERE isnull(nullif(inserted.Version, deleted.Version), nullif(deleted.Version,inserted.Version)) IS NOT NULL
     ) t;
END;  
IF NOT EXISTS(SELECT * FROM INFORMATION_SCHEMA.TABLES WHERE TABLE_NAME= 'History')
CREATE TABLE [dbo].[History](
    [Id] [uniqueidentifier] NOT NULL CONSTRAINT [DF_History_Id]  DEFAULT (newsequentialid()),
    [Tablename] VARCHAR(150),
    [ObjectId] VARCHAR(1500) NOT NULL,
    [Timestamp] [datetime] NOT NULL CONSTRAINT [DF_History_Timestamp]  DEFAULT (getdate()),
    [ChangingUser] [varchar](max) NOT NULL CONSTRAINT [DF_History_ChangingUser]  DEFAULT (suser_sname()),
    [Column] [varchar](max) NOT NULL,
    [OldValue] [nvarchar](max) NULL,
    [NewValue] [nvarchar](max) NULL,
       [ModifiedDate] Datetime NULL
CONSTRAINT [PK_History] PRIMARY KEY CLUSTERED
(
    [Id] ASC
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]
) ON [PRIMARY] TEXTIMAGE_ON [PRIMARY]

IF NOT EXISTS(SELECT * FROM INFORMATION_SCHEMA.TABLES WHERE TABLE_NAME= 'T1')

BEGIN
CREATE TABLE [dbo].[T1](
    [Id] [uniqueidentifier] NOT NULL CONSTRAINT [DF_T1_Id]  DEFAULT (newsequentialid()),
    [Title] text NULL,
    [Amount] [int] NULL,
    [Price] [decimal](18, 7) NULL,
    [Version] [datetime] NOT NULL,
CONSTRAINT [PK_T1] PRIMARY KEY CLUSTERED
(
    [Id] ASC
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]
) ON [PRIMARY] 

INSERT INTO [T1] ([Title],[Amount],[Price],[Version]) VALUES ('Abc',3,372500000 ,'2016-09-01 11:49:33.473'),
                                         (NULL,1,273000000  ,'2016-09-02 11:49:33.473'),
                                         ('Storm Catcher',10,NULL,'2016-09-01 11:49:33.473')
END
IF OBJECT_ID('tempdb..#FiltedTableList') IS NOT NULL
DROP TABLE #FiltedTableList
GO

CREATE TABLE #FiltedTableList
( ID INT IDENTITY(1,1),
  TableName VARCHAR(150))
INSERT INTO #FiltedTableList (TableName)
SELECT 'T1' --here we have only one table to track the changes
DECLARE @TableName sysname,@Counter INT,@Dynamsql varchar(MAX) 
SELECT @Counter=MAX(ID) FROM #FiltedTableList

SET NOCOUNT ON

WHILE (@Counter !=0)

BEGIN

       SELECT @TableName= TableName
       FROM #FiltedTableList
       WHERE ID=@Counter

        DECLARE  @ColumnFilter VARCHAR (MAX)

        SELECT  @ColumnFilter=Stuff((   Select ', ' + C.COLUMN_NAME 
        From INFORMATION_SCHEMA.COLUMNS As C  Where  C.TABLE_NAME = @TableName
               AND c.DATA_TYPE NOT IN ('text','ntext','image')
                Order By C.ORDINAL_POSITION   For Xml Path('')  ), 1, 2, '')


        IF OBJECT_ID('tempdb..##MagInserted') IS NOT NULL
        DROP TABLE ##MagInserted

        IF OBJECT_ID('tempdb..##MagDeleted') IS NOT NULL
        DROP TABLE ##MagDeleted


EXEC('IF OBJECT_ID (''' + @TableName+ '_LogTracker'', ''TR'') IS NOT NULL DROP TRIGGER ' + @TableName+ '_LogTracker')
SELECT @Dynamsql =
 'CREATE TRIGGER ' + @TableName+ '_LogTracker ON ' + @TableName+ ' FOR INSERT, UPDATE, DELETE
  AS
  DECLARE   @column int , @maxColumn int , @char int,@columnname varchar(128) , @TableName varchar(128) , @KeyColumn varchar(1000) , @Dynamsql varchar(2000) ,@dataquery VARCHAR(MAX), 
            @ModifiedDate varchar(21), @UserName varchar(128) , @key int , @Type char(1) , @PKFieldSelect varchar(1000),@PKValueSelect varchar(1000)
  SELECT @TableName = ''' + @TableName+ ''';
  SELECT @UserName = system_user , @ModifiedDate = convert(varchar(8), getdate(), 112) + '' '' + convert(varchar(12), getdate(), 114);
  SELECT '+ @ColumnFilter+' INTO ##MagInserted FROM inserted;SELECT '+ @ColumnFilter+' INTO ##MagDeleted FROM deleted;
   SELECT @KeyColumn = COALESCE(@KeyColumn + '' and'', '' on'') + '' i.'' + c.COLUMN_NAME + '' = d.'' + c.COLUMN_NAME
   FROM INFORMATION_SCHEMA.TABLE_CONSTRAINTS kc JOIN INFORMATION_SCHEMA.KEY_COLUMN_USAGE c ON c.TABLE_NAME = kc.TABLE_NAME and c.CONSTRAINT_NAME = kc.CONSTRAINT_NAME
  WHERE kc.TABLE_NAME = @TableName AND CONSTRAINT_TYPE = ''PRIMARY KEY''
  SELECT @PKFieldSelect = COALESCE(@PKFieldSelect+''+'','''') + '''''''' + COLUMN_NAME + ''''''''
   FROM INFORMATION_SCHEMA.TABLE_CONSTRAINTS kc JOIN INFORMATION_SCHEMA.KEY_COLUMN_USAGE c ON c.TABLE_NAME = kc.TABLE_NAME and c.CONSTRAINT_NAME = kc.CONSTRAINT_NAME
  WHERE kc.TABLE_NAME = @TableName AND CONSTRAINT_TYPE = ''PRIMARY KEY''
  SELECT @PKValueSelect = coalesce(@PKValueSelect+''+'','''') + ''convert(varchar(100), coalesce(i.'' + COLUMN_NAME + '',d.'' + COLUMN_NAME + ''))''
  FROM INFORMATION_SCHEMA.TABLE_CONSTRAINTS kc JOIN INFORMATION_SCHEMA.KEY_COLUMN_USAGE c ON c.TABLE_NAME = kc.TABLE_NAME  and c.CONSTRAINT_NAME = kc.CONSTRAINT_NAME
  WHERE  kc.TABLE_NAME = @TableName  AND CONSTRAINT_TYPE = ''PRIMARY KEY''  
  SELECT @column = 0 , @maxColumn = max(ORDINAL_POSITION) FROM INFORMATION_SCHEMA.COLUMNS WHERE TABLE_NAME = @TableName 
              WHILE @column < @maxColumn
              BEGIN
                     SELECT @column = min(ORDINAL_POSITION) FROM INFORMATION_SCHEMA.COLUMNS WHERE TABLE_NAME = @TableName AND ORDINAL_POSITION > @column
                     SELECT @key = (@column - 1 )% 8 + 1; SELECT @key = power(2,@key - 1);SELECT @char = ((@column - 1) / 8) + 1
                   IF SUBSTRING(COLUMNS_UPDATED(),@char, 1) & @key > 0 OR @Type IN (''I'',''D'')
                           BEGIN
                           SELECT @columnname = COLUMN_NAME from INFORMATION_SCHEMA.COLUMNS where TABLE_NAME = @TableName and ORDINAL_POSITION = @column
                           SELECT @Dynamsql = ''insert History (TableName,[ObjectId], [Column], OldValue, NewValue, ModifiedDate, ChangingUser)''
                           SELECT @Dynamsql = @Dynamsql + '' select '''''' + @TableName + '''''''' 
                           SELECT @Dynamsql = @Dynamsql +  '','' + @PKValueSelect
                           SELECT @Dynamsql = @Dynamsql + '','''''' + @columnname + ''''''''
                           SELECT @Dynamsql = @Dynamsql + '',convert(varchar(1000),d.'' + @columnname + '')''
                           SELECT @Dynamsql = @Dynamsql + '',convert(varchar(1000),i.'' + @columnname + '')''
                           SELECT @Dynamsql = @Dynamsql + '','''''' + @ModifiedDate + ''''''''
                           SELECT @Dynamsql = @Dynamsql + '','''''' + @UserName + ''''''''
                           SELECT @Dynamsql = @Dynamsql + '' from ##MagInserted i full outer join ##MagDeleted d''
                           SELECT @Dynamsql = @Dynamsql + @KeyColumn
                           SELECT @Dynamsql = @Dynamsql + '' where i.'' + @columnname + '' <> d.'' + @columnname
                           SELECT @Dynamsql = @Dynamsql + '' or (i.'' + @columnname + '' is null and  d.'' + @columnname + '' is not null)''
                           SELECT @Dynamsql = @Dynamsql + '' or (i.'' + @columnname + '' is not null and  d.'' + @columnname + '' is null)''
                           EXEC (@Dynamsql)
                           END    END   '
SELECT @Dynamsql
EXEC(@Dynamsql)

SET @Counter=@Counter-1

END