不指定列名的 SQL 合并功能

标签 sql sql-server merge dynamic-sql

我正在从我的 Web 应用程序执行 SQLBulkCopy 并将记录插入到临时表中。这是我第一次使用临时表。将接受数据的实时表有大约 200 个字段,并且可以在 future 更改。当发生这种变化时,我不想重新编写合并语句。

我想出了这个模仿合并功能的 SQL,但不需要我拼出表列。我不是 SQL 专家,希望有人来看看,如果您发现使用此 SQL 可能出现的任何问题,请告诉我,因为我还没有看到任何此类示例,而且很多人都在搜索。

请注意,将插入临时表中具有空 id 字段的记录。

-- set the table names, primary key field & vars to hold query parts
DECLARE @LiveTable varchar(20) = 'Test'
DECLARE @StagingTable varchar(20) = 'TestStaging'
DECLARE @PKField varchar(20) = 'TestPK'
DECLARE @SQLSet nvarchar(MAX) = ''
DECLARE @SQLInsertFields nvarchar(MAX) = ''

-- get comma delimited field names
DECLARE @Fields nvarchar(MAX) = (SELECT dbo.fn_GetCommaDelimitedFieldNames(@LiveTable))

-- loop through fields generating set clause of query to execute
WHILE LEN(@Fields) > 0
BEGIN
    DECLARE @Field varchar(50) = left(@Fields, CHARINDEX(',', @Fields+',')-1)
    IF @Field <> @PKField -- the primary key field cannot be updated
        BEGIN
            SET @SQLSet += ', ' + @LiveTable + '.' + @Field + ' = ' + @StagingTable + '.' + @Field
            SET @SQLInsertFields += ', ' + @Field
        END
    SET @Fields = STUFF(@Fields, 1, CHARINDEX(',', @Fields+','), '')
END

-- remove the leading comma
SET @SQLSet = SUBSTRING(@SQLSet,3,LEN(@SQLSet))
SET @SQLInsertFields = SUBSTRING(@SQLInsertFields,3,LEN(@SQLInsertFields))

-- update records from staging table where primary key is provided
DECLARE @SQL nvarchar(MAX) = N'UPDATE ' + @LiveTable + 
                             ' SET ' + @SQLSet + 
                             ' FROM ' + @LiveTable + 
                             ' INNER JOIN ' + @StagingTable + 
                             ' ON ' + @LiveTable + '.' + @PKField + ' = ' + @StagingTable + '.' + @PKField

-- insert records from staging table where primary key is null
SET @SQL += '; INSERT INTO ' + @LiveTable + ' (' + @SQLInsertFields + ') SELECT ' + @SQLInsertFields + ' FROM ' + @StagingTable + ' WHERE ' + @PKField + ' IS NULL'

-- delete the records from the staging table
SET @SQL += '; DELETE FROM ' + @StagingTable

-- execute the sql statement to update existing records and insert new records
exec sp_executesql @SQL;

如果有人看到性能或其他任何问题,我很欣赏这种洞察力。

最佳答案

不要这样做。真的。您正在非常努力地避免出现在时机成熟时您可能无法正确处理的罕见问题。

如果目标表发生变化,您怎么知道它会发生变化,使您喜欢的动态 SQL 能够正常工作?你怎么能确定它似乎不起作用——即在语法上会起作用——但实际上做错了事?如果目标表发生更改,您是否不必更改应用程序以及临时表?空气中的所有这些,还有什么添加一个SET条款?

与此同时,怎么能指望任何人阅读那个 gobbledygook(不是你的错,真的,那是 SQL 的语法)?一个沼泽标准的插入语句将非常清晰和可靠。

而且很快。 SQL Server 无法优化您的动态查询。您使用 bcp 来提高效率,现在您正在以良好的 future 证明来击败它。

关于不指定列名的 SQL 合并功能,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/15376080/

相关文章:

SQL - 计算一个属性,按另一个分组

sql - PostgreSQL 中的 TRIGGER ON VIEW 不会触发

sql-server - 两行相减

java - 这是合并排序吗?

sql - 需要 SQL MIN MAX Group By 和 AGGREGATE 的帮助

mysql - SQL 语法 UPDATE 语句

sql-server - 将 CSV 文件导入 SQL Server 时操作停止

SQL Server - 高级分组

mysql - 将两个表中的两列合并为一个

merge - 使用 MapReduce 获取大文件中的重复记录