1

我正在尝试将一个非常宽的表从源(链接的 Oracle 服务器)合并到目标表(SQL Server 2012),而不列出所有列。除了其中的记录外,这两个表都是相同的。这是我一直在使用的:

TRUNCATE TABLE TargetTable
INSERT INTO TargetTable
SELECT *
FROM SourceTable

当/如果我得到这个工作,我想把它变成一个过程,这样我就可以将更新所需的源、目标和匹配键传递给它。现在我只想让它工作。

USE ThisDatabase  
GO

DECLARE
  @Columns VARCHAR(4000) = (
    SELECT COLUMN_NAME + ',' 
    FROM INFORMATION_SCHEMA.COLUMNS 
    WHERE TABLE_NAME = 'TargetTable' 
    FOR XML PATH('')
    )

MERGE TargetTable AS T

USING (SELECT * FROM SourceTable) AS S
ON (T.ID = S.ID AND T.ROWVERSION = S.ROWVERSION)

WHEN MATCHED THEN 
  UPDATE SET @Columns = S.@Columns

WHEN NOT MATCHED THEN   
  INSERT (@Columns)
  VALUES (S.@Columns)

请原谅我的菜鸟。我觉得我只完成了一半,但我对 SQL 的某些部分还不够了解,无法将它们放在一起。非常感谢。

4

2 回答 2

1

正如前面在答案中提到的,如果您不想指定 columns ,那么您必须编写一个动态查询。在您的情况下,这样的事情应该会有所帮助:

DECLARE
@Columns VARCHAR(4000) = (
SELECT COLUMN_NAME + ',' 
FROM INFORMATION_SCHEMA.COLUMNS 
WHERE TABLE_NAME = 'TargetTable' 
FOR XML PATH('')
)

DECLARE  @MergeQuery NVARCHAR(MAX)
DECLARE  @UpdateQuery VARCHAR(MAX)
DECLARE  @InsertQuery VARCHAR(MAX)
DECLARE  @InsertQueryValues VARCHAR(MAX)
DECLARE  @Col VARCHAR(200)

SET @UpdateQuery='Update Set '
SET @InsertQuery='Insert ('
SET @InsertQueryValues=' Values('


WHILE LEN(@Columns) > 0
BEGIN
   SET @Col=left(@Columns, charindex(',', @Columns+',')-1);

   IF @Col<> 'ID' AND @Col <> 'ROWVERSION'
   BEGIN
      SET @UpdateQuery= @UpdateQuery+ 'TargetTable.'+ @Col + ' = SourceTable.'+ @Col+ ','
      SET @InsertQuery= @InsertQuery+@Col + ','
     SET @InsertQueryValues=@InsertQueryValues+'SourceTable.'+ @Col+ ','
   END

  SET @Columns = stuff(@Columns, 1, charindex(',', @Columns+','), '')
END

SET @UpdateQuery=LEFT(@UpdateQuery, LEN(@UpdateQuery) - 1)
SET @InsertQuery=LEFT(@InsertQuery, LEN(@InsertQuery) - 1)
SET @InsertQueryValues=LEFT(@InsertQueryValues, LEN(@InsertQueryValues) - 1)

SET @InsertQuery=@InsertQuery+ ')'+  @InsertQueryValues +')'

SET @MergeQuery=
N'MERGE TargetTable
USING SourceTable
ON TargetTable.ID = SourceTable.ID AND TargetTable.ROWVERSION =    SourceTable.ROWVERSION ' +

'WHEN MATCHED THEN ' + @UpdateQuery +
' WHEN NOT MATCHED THEN '+@InsertQuery +';'

Execute sp_executesql @MergeQuery

如果你想了解更多关于 Merge 的信息,你可以阅读这篇优秀的文章

于 2015-04-16T05:50:55.023 回答
0

不要心情不好。这需要时间。合并有有趣的语法。我实际上从未使用过它。我阅读了微软关于它的文档,它非常有帮助,甚至还有示例。我想我涵盖了一切。我认为您可能需要进行少量调整,但我认为它应该可以工作。

这是 MERGE 的文档: https ://msdn.microsoft.com/en-us/library/bb510625.aspx

至于你的代码,我评论了几乎所有的东西来解释它并向你展示如何去做。

这部分是为了帮助编写你的合并语句

USE ThisDatabase    --This says what datbase context to use.
                    --Pretty much what database your querying.
                    --Like this: database.schema.objectName
GO

DECLARE
  @SetColumns VARCHAR(4000) = (
    SELECT CONCAT(QUOTENAME(COLUMN_NAME),' = S.',QUOTENAME(COLUMN_NAME),',',CHAR(10))   --Concat just says concatenate these values. It's adds the strings together.
                                                                                        --QUOTENAME adds brackets around the column names
                                                                                        --CHAR(10) is a line break for formatting purposes(totally optional)
    FROM INFORMATION_SCHEMA.COLUMNS 
    --WHERE TABLE_NAME = 'TargetTable' 
    FOR XML PATH('')
    )   --This uses some fancy XML trick to get your Columns concatenated into one row. 
        --What really is in your table is a column of your column names in different rows.
        --BTW If the columns names in both tables are identical, then this will work.
DECLARE @Columns VARCHAR(4000) = (
    SELECT QUOTENAME(COLUMN_NAME) + ','


    FROM INFORMATION_SCHEMA.COLUMNS 
    --WHERE TABLE_NAME = 'TargetTable' 
    FOR XML PATH('')
    )

SET @Columns = SUBSTRING(@Columns,0,LEN(@Columns)) -- this gets rid off the comma at the end of your list
SET @SetColumns = SUBSTRING(@SetColumns,0,LEN(@SetColumns)) --same thing here

SELECT @SetColumns --Your going to want to copy and paste this into your WHEN MATCHED statement
SELECT @Columns --Your going to want to copy this into your WHEN NOT MATCHED statement
GO

合并声明

尤其是看看我关于 ROWVERSION 的笔记。

MERGE INTO TargetTable AS T

USING SourceTable AS S --Don't really need to write SELECT * FROM since you need the whole table anyway
ON (T.ID = S.ID AND T.[ROWVERSION] = S.[ROWVERSION])    --These are your matching parameters
                                                        --One note on this, if ROWVERSION is different versions of the same data you don't want to have RowVersion here
                                                        --Like lets say you have ID 1 ROWVERSION 2 in your source but only version 1 in your targetTable
                                                        --If you leave T.ID =S.ID AND T.ROWVERSION = S.ROWVERSION, then it will insert the new ROWVERSION
                                                        --So you'll have two versions of ID 1

WHEN MATCHED THEN                   --When TargetTable ID and ROWVERSION match in the matching parameters
                                    --Update the values in the TargetTable
    UPDATE SET /*Copy and Paste @SetColumnss here*/
                --Should look like this(minus the "--"):
                --Col1 = S.Col1,
                --Col2 = S.Col2,
                --Col3 = S.Col3,
                --Etc...

WHEN NOT MATCHED THEN   --This says okay there are no rows with the existing ID, now insert a new row
  INSERT (col1,col2,col3) --Copy and paste @Columns in between the parentheses. Should look like I show it. Note: This is insert into target table so your listing the target table columns
  VALUES (col1,col2,col3)       --Same thing here. This is the list of source table columns
于 2015-04-16T05:34:49.167 回答