Win*_*nch 5 sql sql-server primary-key sql-merge sql-server-2016
我正在编写一个查询来将数据从一个表导入到一个新表中.我需要插入新表中不存在的记录,并更新确实存在的记录.我正在尝试使用MERGE"upsert"方法.
由于客户端的数据库和应用程序结构,我有一些独特的问题.我插入的表有一个唯一ID字段,每个新行增加1,但表不执行自动递增; insert语句需要拉出目标表中的最高ID,并为新记录添加1.
根据我的研究,我无法弄清楚如何用MERGE做到这一点.我没有数据库权限来创建序列.我尝试了很多东西,但目前我的查询看起来像:
MERGE
dbo.targetTable as target
USING
dbo.sourceTable AS source
ON
target.account_no = source.account_ID
WHEN NOT MATCHED THEN
INSERT (
ID,
FIELD1,
FIELD2,
FIELD3
) VALUES (
(SELECT MAX(ID) + 1 FROM dbo.targetTable),
'field1',
'field2',
'field3'
)
Run Code Online (Sandbox Code Playgroud)
我遇到这个代码的问题是它似乎只运行一次新ID的select语句.也就是说,如果目标表中的最高ID是10,它将插入ID为11的每个新记录.这将无法正常工作,因为我收到
Violation of PRIMARY KEY constraint. Cannot insert duplicate key in object错误.我一直在做大量的谷歌搜索和尝试不同的东西,但无法弄清楚这一点.感谢任何帮助,谢谢.
编辑:为了澄清,唯一ID列不会自动填充.如果我没有为ID列插入值,我得到
Cannot insert the value NULL into column 'ID', table 'dbo.targetTable'; column does not allow nulls. UPDATE fails.
而且,正如我最初提到的,我没有创建序列的权限.它只是抛出一个错误,并说我没有这样做的许可.
我同意将ID列自动更改为自动增量是完美的,但我没有能力像这样修改表格.
如果不需要连续的ID,可以将最后一个可用的ID添加ID到a中ROW_NUMBER()以生成新的、不重复的ID。
BEGIN TRANSACTION
DECLARE @NextAvailableID INT = (SELECT ISNULL(MAX(ID), 0) FROM dbo.targetTable WITH (TABLOCKX))
;WITH SourceWithNewIDs AS
(
SELECT
S.*,
NewID = @NextAvailableID + ROW_NUMBER() OVER (ORDER BY S.account_ID)
FROM
dbo.sourceTable AS S
)
MERGE
dbo.targetTable as target
USING
SourceWithNewIDs AS source
ON
target.account_no = source.account_ID
WHEN NOT MATCHED THEN
INSERT (
ID,
FIELD1,
FIELD2,
FIELD3
) VALUES (
NewID,
'field1',
'field2',
'field3'
)
COMMIT
Run Code Online (Sandbox Code Playgroud)
请记住,此示例缺少回滚的正确错误处理,并且用于检索最大 ID 的锁将阻止所有其他操作,直到提交或回滚。
如果您需要新行具有连续的 ID,那么您可以使用相同的方法与常规INSERT(with WHERE NOT EXISTS...) 而不是 a MERGE(必须UPDATE单独编写)。