MERGE而不在SQL Server 2008中指定列名

Gan*_*shT 14 sql-server sql-server-2008

我看着MERGE看起来很酷的命令,但仍需要指定列.我正在寻找类似的东西:

MERGE INTO target AS t
USING source AS s          
WHEN MATCHED THEN
    UPDATE SET
    [all t.fields = s.fields]
WHEN NOT MATCHED THEN 
      INSERT ([all fields])
      VALUES ([all s.fields])
Run Code Online (Sandbox Code Playgroud)

可能吗?

Bil*_*ham 15

我很懒...这是我编写的一个便宜的proc,会为表格吐出一般的MERGE命令.它在information_schema.columns中查询列名.我删除了我的源数据库名称 - 所以,你必须更新proc以使用你的数据库(寻找@SourceDB ......我说它很便宜.)无论如何,我知道其他人可以写得更好 - 它服务于我目的很好.(它做了一些假设,你可以把逻辑放在处理中 - 即关闭IDENTITY_INSERT - 即使表没有标识列.)它更新当前上下文中的表.它是针对sql server 2008编写的,用于同步一些表.当然,使用风险自负.

    CREATE PROCEDURE [dbo].[GenerateMergeSQL]
    @TableName varchar(100)
AS
BEGIN
    SET NOCOUNT ON 

    declare @sql varchar(5000),@SourceInsertColumns varchar(5000),@DestInsertColumns varchar(5000),@UpdateClause varchar(5000)
    declare @ColumnName varchar(100), @identityColName varchar(100)
    declare @IsIdentity int,@IsComputed int, @Data_Type varchar(50)

    declare @SourceDB as varchar(200)


    -- source/dest i.e. 'instance.catalog.owner.' - table names will be appended to this
    -- the destination is your current db context
    set @SourceDB = '[mylinkedserver].catalog.myDBOwner.'

    set @sql = ''
    set @SourceInsertColumns  = ''
    set @DestInsertColumns  = ''
    set @UpdateClause  = ''
    set @ColumnName  = ''
    set @isIdentity = 0
    set @IsComputed = 0
    set @identityColName  = ''
    set @Data_Type  = ''


DECLARE @ColNames CURSOR
SET @ColNames = CURSOR FOR 
    select column_name, COLUMNPROPERTY(object_id(TABLE_NAME), COLUMN_NAME, 'IsIdentity') as IsIdentity ,
        COLUMNPROPERTY(object_id(TABLE_NAME), COLUMN_NAME, 'IsComputed') as IsComputed , DATA_TYPE
    from information_schema.columns where table_name = @TableName order by ordinal_position

OPEN @ColNames
FETCH NEXT FROM @ColNames INTO @ColumnName, @isIdentity, @IsComputed, @DATA_TYPE

WHILE @@FETCH_STATUS = 0
    BEGIN
        if @IsComputed = 0 and @DATA_TYPE <> 'timestamp'
        BEGIN
            set @SourceInsertColumns = @SourceInsertColumns + 
                case when @SourceInsertColumns = '' THEN '' ELSE ',' end +
                'S.' + @ColumnName

            set @DestInsertColumns = @DestInsertColumns + 
                case when @DestInsertColumns = '' THEN '' ELSE ',' end +
                @ColumnName

            if @isIdentity = 0
            BEGIN
                set @UpdateClause = @UpdateClause + 
                case when @UpdateClause = '' THEN '' ELSE ',' end
                 + @ColumnName + ' = ' + 'S.' + @ColumnName + char(10)
            END

            if @isIdentity = 1 set @identityColName = @ColumnName
        END

        FETCH NEXT FROM @ColNames INTO @ColumnName, @isIdentity, @IsComputed, @DATA_TYPE
    END

CLOSE @ColNames
DEALLOCATE @ColNames

    SET @sql = 'SET IDENTITY_INSERT ' + @TableName + ' ON;
            MERGE ' + @TableName + ' AS D
                USING ' + @SourceDB + @TableName + ' AS S
                ON (D.' + @identityColName + ' = S.' + @identityColName + ')
            WHEN NOT MATCHED BY TARGET
                THEN INSERT(' + @DestInsertColumns + ') 
                VALUES(' + @SourceInsertColumns + ')
            WHEN MATCHED 
                THEN UPDATE SET 
                    ' + @UpdateClause + '
            WHEN NOT MATCHED BY SOURCE
                THEN DELETE
            OUTPUT $action, Inserted.*, Deleted.*;
            SET IDENTITY_INSERT ' + @TableName + ' OFF'

    Print @SQL

END
Run Code Online (Sandbox Code Playgroud)


Cha*_*ins 7

不是你想要的一切,而是部分:

WHEN NOT MATCHED THEN
INSERT([all fields])
VALUES (field1, field2, ...)

(值列表必须完整,并匹配表定义中字段的顺序.)

  • @gangt - 这是一个非常好的问题,我很高兴你问过它.尽管其他人可能已经说过,但在编程方面,"懒惰"在许多方面都是一种美德.每当较少的打字转换为较少的工作和较少的错误,我们称之为"提高效率",而不是"懒惰".太好了. (8认同)