T-SQL - 合并从源到目标的所有列 table w/o 列出所有列
T-SQL - Merge all columns from source to target table w/o listing all the columns
我正在尝试将来自源(链接的 Oracle 服务器)的非常广泛的 table 合并到目标 table(SQL Server 2012)w/o 列表所有列。两个 table 除了其中的记录外,其他都是相同的。
这是我一直在使用的:
TRUNCATE TABLE TargetTable
INSERT INTO TargetTable
SELECT *
FROM SourceTable
When/if 我得到了这个工作 我想让它成为一个过程,以便我可以将进行更新所需的源、目标和匹配键传递给它。现在我只想让它工作。
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 的某些部分理解得不够好,无法将它们放在一起。非常感谢。
不要难过。这需要时间。 Merge 有有趣的语法。我实际上从未使用过它。我阅读了微软关于它的文档,非常有帮助,甚至还有示例。我想我涵盖了一切。我认为您可能需要做一些微调,但我认为它应该有效。
这是 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
正如前面答案中提到的,如果您不想指定列,则必须编写动态查询。
在你的情况下这样的事情应该有所帮助:
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
If you want more information about Merge, you could read the this excellent article
我正在尝试将来自源(链接的 Oracle 服务器)的非常广泛的 table 合并到目标 table(SQL Server 2012)w/o 列表所有列。两个 table 除了其中的记录外,其他都是相同的。 这是我一直在使用的:
TRUNCATE TABLE TargetTable
INSERT INTO TargetTable
SELECT *
FROM SourceTable
When/if 我得到了这个工作 我想让它成为一个过程,以便我可以将进行更新所需的源、目标和匹配键传递给它。现在我只想让它工作。
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 的某些部分理解得不够好,无法将它们放在一起。非常感谢。
不要难过。这需要时间。 Merge 有有趣的语法。我实际上从未使用过它。我阅读了微软关于它的文档,非常有帮助,甚至还有示例。我想我涵盖了一切。我认为您可能需要做一些微调,但我认为它应该有效。
这是 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
正如前面答案中提到的,如果您不想指定列,则必须编写动态查询。 在你的情况下这样的事情应该有所帮助:
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
If you want more information about Merge, you could read the this excellent article