动态插入语句需要返回插入的ID

时间:2019-04-25 19:53:05

标签: sql sql-server

我有一个已经完成的触发器,并且在触发器操作期间,我将一些记录插入到主表中,然后需要使用主表中的ID将一些记录插入到明细表中。

我不确定插入后如何从主表中获取ID,以便可以在明细表中使用。这是我的触发代码:

IF EXISTS(SELECT * FROM INFORMATION_SCHEMA.TABLES 
          WHERE TABLE_NAME= 'DATA_HIL_Master')
BEGIN
    DECLARE @sql NVARCHAR(MAX), 
            @TABLE_NAME sysname

    SET NOCOUNT ON

    SELECT @TABLE_NAME = MIN(TABLE_NAME) 
    FROM INFORMATION_SCHEMA.Tables 
    WHERE TABLE_TYPE = 'BASE TABLE' 
      AND TABLE_NAME != 'sysdiagrams'
      AND TABLE_NAME != 'Audit'
      AND TABLE_NAME = 'ADM_Gate'

    WHILE @TABLE_NAME IS NOT NULL
    BEGIN
        EXEC('IF OBJECT_ID (''' + @TABLE_NAME + '_ChangeTracking'', ''TR'') IS NOT NULL DROP TRIGGER ' + @TABLE_NAME + '_ChangeTracking')
        SELECT @sql = 
    'create trigger ' + @TABLE_NAME + '_ChangeTracking on ' + @TABLE_NAME + ' for insert, update, delete
    as
    declare @bit int ,
    @field int ,
    @maxfield int ,
    @char int ,
    @fieldname varchar(128) ,
    @TableName varchar(128) ,
    @PKCols varchar(1000) ,
    @sql nvarchar(max), 
    @Type int ,
    @PKFieldSelect varchar(1000),
    @PKValueSelect varchar(1000),
    @MasterId nvarchar(1)

    select @TableName = ''' + @TABLE_NAME + '''

    if exists (select * from inserted)
    if exists (select * from deleted)
    select @Type = 2
    else
    select @Type = 3
    else
    select @Type = 1

    select * into #ins from inserted
    select * into #del from deleted

    select @PKCols = coalesce(@PKCols + '' and'', '' on'') + '' i.'' + c.COLUMN_NAME + '' = d.'' + c.COLUMN_NAME
    from INFORMATION_SCHEMA.TABLE_CONSTRAINTS pk 
        INNER JOIN INFORMATION_SCHEMA.KEY_COLUMN_USAGE c on c.CONSTRAINT_NAME = pk.CONSTRAINT_NAME and c.TABLE_NAME = pk.TABLE_NAME
    where pk.TABLE_NAME = @TableName
        and CONSTRAINT_TYPE = ''PRIMARY KEY''

    select @PKFieldSelect = coalesce(@PKFieldSelect + ''+'', '''') + '''''''' + COLUMN_NAME + ''''''''
    FROM    INFORMATION_SCHEMA.TABLE_CONSTRAINTS pk 
            INNER JOIN INFORMATION_SCHEMA.KEY_COLUMN_USAGE c on c.CONSTRAINT_NAME = pk.CONSTRAINT_NAME and c.TABLE_NAME = pk.TABLE_NAME
    WHERE   pk.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 pk    
      INNER JOIN INFORMATION_SCHEMA.KEY_COLUMN_USAGE c on c.CONSTRAINT_NAME = pk.CONSTRAINT_NAME and c.TABLE_NAME = pk.TABLE_NAME  
    where  pk.TABLE_NAME = @TableName   
    and CONSTRAINT_TYPE = ''PRIMARY KEY'' 


    select @sql = ''insert DATA_HIL_Master (OperationType, ReferenceTable, ReferenceId, Last_UserId_Log, Last_WorkstationId_Log, Last_DateTime_Log)''
    if @Type = 1
        select @sql = @sql + '' select 1 ''
    if @Type = 2
        select @sql = @sql + '' select 2 ''
    if @Type = 3
        select @sql = @sql + '' select 3''  

    select @sql = @sql + '', '''''' + @TableName + ''''''''     
    select @sql = @sql + '','' + @PKValueSelect     
    select @sql = @sql + '',convert(varchar(1000),i.Last_UserId_Log)''
    select @sql = @sql + '',convert(varchar(1000),i.Last_WorkstationId_Log)''
    select @sql = @sql + '',convert(varchar(1000),i.Last_DateTime_Log)''
    select @sql = @sql + '' from #ins i full outer join #del d''
    select @sql = @sql + @PKCols 
    EXECUTE sp_executesql @sql
    select @MasterId    

    select @field = 0, 
           @maxfield = max(ORDINAL_POSITION) 
      from INFORMATION_SCHEMA.COLUMNS 
     where TABLE_NAME = @TableName

    while @field < @maxfield
    begin
        select @field = min(ORDINAL_POSITION) 
          from INFORMATION_SCHEMA.COLUMNS 
         where TABLE_NAME = @TableName 
          and ORDINAL_POSITION > @field

        select @bit = (@field - 1 )% 8 + 1
        select @bit = power(2,@bit - 1)
        select @char = ((@field - 1) / 8) + 1

        if substring(COLUMNS_UPDATED(),@char, 1) & @bit > 0 or @Type in (1,3)
        begin
            select @fieldname = COLUMN_NAME from INFORMATION_SCHEMA.COLUMNS where TABLE_NAME = @TableName and ORDINAL_POSITION = @field
            select @sql = ''insert data_HIL_Detail (MasterId, ColumnName, OriginalValue, ModifiedValue)''
            select @sql = @sql + '' select convert(varchar(1000),'' + @MasterId + '')''
            select @sql = @sql + '','''''' + @fieldname + ''''''''
            select @sql = @sql + '', convert(varchar(1000),d.'' + @fieldname + '')''
            select @sql = @sql + '', convert(varchar(1000),i.'' + @fieldname + '')''
            select @sql = @sql + '' from #ins i full outer join #del d''
            select @sql = @sql + @PKCols
            select @sql = @sql + '' where i.'' + @fieldname + '' <> d.'' + @fieldname
            select @sql = @sql + '' or (i.'' + @fieldname + '' is null and  d.'' + @fieldname + '' is not null)''
            select @sql = @sql + '' or (i.'' + @fieldname + '' is not null and  d.'' + @fieldname + '' is null)''
            select @sql

        end
    END '

    SELECT @sql
    EXEC(@sql)
    SELECT @TABLE_NAME = MIN(TABLE_NAME) 
      FROM INFORMATION_SCHEMA.Tables 
     WHERE TABLE_NAME> @TABLE_NAME
       AND TABLE_TYPE= 'BASE TABLE' 
       AND TABLE_NAME!= 'sysdiagrams'
       AND TABLE_NAME!= 'Audit'
       AND TABLE_NAME = 'ADM_Gate'
    END
END

1 个答案:

答案 0 :(得分:0)

WEI_DBA上面提到了SCOPE_IDENTITY(),但是有一个复杂性会影响您,因为sp_executeSQL语句执行的代码实际上与触发器不在同一范围内。但是,通过在sp_executeSQL调用中使用OUTPUT参数,可以轻松解决此问题。您使用NVARCHAR(1)数据类型作为ID,然后将其强制转换为VARCHAR(1000)并没有多大意义,但在本示例中,我将使用它。考虑一下您的触发器中的这段代码摘录。我将其重写为使用也称为@MasterID的输出参数:

select @sql = @sql + '' from #ins i full outer join #del d''
select @sql = @sql + @PKCols + ''; SET @MasterId = SCOPE_IDENTITY() -- Or whatever your ID is''

DECLARE @Parms nvarchar(40)

SET @Parms = N''@MasterId Nvarchar(1) OUTPUT'';

EXECUTE sp_executesql @sql, @Parms, @MasterId = @MasterId Output
--  select @MasterId    -- @MasterId is set to the @MasterId returned by sp_executesql

这时,@ MasterId具有动态SQL语句中代码返回的值。