这个 T-SQL MERGE 语句有什么问题?
我是 MERGE
新手,我确信我的代码中有一些错误。
此代码将运行并创建我的场景:
我有两个表,一个名为 TempUpsert
,由 SqlBulkCopy
操作填充(数以百万计的记录),另一个 >销售
表,保存要索引和使用的生产数据。
我希望将 TempUpsert
表与 Sales
表合并
我显然做错了什么,因为即使是最小的示例也会失败
IF EXISTS (SELECT * FROM sys.objects WHERE object_id = OBJECT_ID(N'[dbo].[TempUpsert]') )
drop table TempUpsert;
CREATE TABLE [dbo].[TempUpsert](
[FirstName] [varchar](200) NOT NULL,
[LastName] [varchar](200) NOT NULL,
[Score] [int] NOT NULL
) ON [PRIMARY] ;
CREATE TABLE [dbo].[Sales](
[FullName] [varchar](200) NOT NULL,
[LastName] [varchar](200) NOT NULL,
[FirstName] [varchar](200) NOT NULL,
[lastUpdated] [date] NOT NULL,
CONSTRAINT [PK_Sales] PRIMARY KEY CLUSTERED
(
[FullName] ASC
)
---- PROC
CREATE PROCEDURE [dbo].[sp_MoveFromTempUpsert_to_Sales]
(@HashMod int)
AS
BEGIN
-- SET NOCOUNT ON added to prevent extra result sets from
-- interfering with SELECT statements.
SET NOCOUNT ON;
MERGE Sales AS trget
USING (
SELECT
--- Edit: Thanks to Mikal added DISTINCT
DISTINCT
FirstName, LastName , [Score], LastName+'.'+FirstName AS FullName
FROM TempUpsert AS ups) AS src (FirstName, LastName, [Score], FullName)
ON
(
src.[Score] = @hashMod
AND
trget.FullName=src.FullName
)
WHEN MATCHED
THEN
UPDATE SET trget.lastUpdated = GetDate()
WHEN NOT MATCHED
THEN INSERT ([FullName], [LastName], [FirstName], [lastUpdated])
VALUES (FullName, src.LastName, src.FirstName, GetDate())
OUTPUT $action, Inserted.*, Deleted.* ;
--print @@rowcount
END
GO
--- Insert dummie data
INSERT INTO TempUpsert (FirstName, LastName, Score)
VALUES ('John','Smith',2);
INSERT INTO TempUpsert (FirstName, LastName, Score)
VALUES ('John','Block',2);
INSERT INTO TempUpsert (FirstName, LastName, Score)
VALUES ('John','Smith',2); --make multiple on purpose
----- EXECUTE PROC
GO
DECLARE @return_value int
EXEC @return_value = [dbo].[sp_MoveFromTempUpsert_to_Sales]
@HashMod = 2
SELECT 'Return Value' = @return_value
GO
这返回:
(1 行受影响)
(1 行受影响)
(1 行受影响)消息 2627,级别 14,状态 1,过程 sp_MoveFromTempUpsert_to_Sales,第 12 行
违反主键约束“PK_Sales”。无法在对象中插入重复的键 'dbo.销售'。该声明已终止。(1 行受影响)
请问我做错了什么?
非常感谢
I am new to MERGE
, and I'm sure I have some error in my code.
This code will run and create my scenario:
I have two tables, one that is called TempUpsert
that fills from a SqlBulkCopy
operation (100s of millions of records) and a Sales
table that holds the production data which is to be indexed and used.
I wish to merge the TempUpsert
table with the Sales
one
I am obviously doing something wrong as it fails with even the smallest example
IF EXISTS (SELECT * FROM sys.objects WHERE object_id = OBJECT_ID(N'[dbo].[TempUpsert]') )
drop table TempUpsert;
CREATE TABLE [dbo].[TempUpsert](
[FirstName] [varchar](200) NOT NULL,
[LastName] [varchar](200) NOT NULL,
[Score] [int] NOT NULL
) ON [PRIMARY] ;
CREATE TABLE [dbo].[Sales](
[FullName] [varchar](200) NOT NULL,
[LastName] [varchar](200) NOT NULL,
[FirstName] [varchar](200) NOT NULL,
[lastUpdated] [date] NOT NULL,
CONSTRAINT [PK_Sales] PRIMARY KEY CLUSTERED
(
[FullName] ASC
)
---- PROC
CREATE PROCEDURE [dbo].[sp_MoveFromTempUpsert_to_Sales]
(@HashMod int)
AS
BEGIN
-- SET NOCOUNT ON added to prevent extra result sets from
-- interfering with SELECT statements.
SET NOCOUNT ON;
MERGE Sales AS trget
USING (
SELECT
--- Edit: Thanks to Mikal added DISTINCT
DISTINCT
FirstName, LastName , [Score], LastName+'.'+FirstName AS FullName
FROM TempUpsert AS ups) AS src (FirstName, LastName, [Score], FullName)
ON
(
src.[Score] = @hashMod
AND
trget.FullName=src.FullName
)
WHEN MATCHED
THEN
UPDATE SET trget.lastUpdated = GetDate()
WHEN NOT MATCHED
THEN INSERT ([FullName], [LastName], [FirstName], [lastUpdated])
VALUES (FullName, src.LastName, src.FirstName, GetDate())
OUTPUT $action, Inserted.*, Deleted.* ;
--print @@rowcount
END
GO
--- Insert dummie data
INSERT INTO TempUpsert (FirstName, LastName, Score)
VALUES ('John','Smith',2);
INSERT INTO TempUpsert (FirstName, LastName, Score)
VALUES ('John','Block',2);
INSERT INTO TempUpsert (FirstName, LastName, Score)
VALUES ('John','Smith',2); --make multiple on purpose
----- EXECUTE PROC
GO
DECLARE @return_value int
EXEC @return_value = [dbo].[sp_MoveFromTempUpsert_to_Sales]
@HashMod = 2
SELECT 'Return Value' = @return_value
GO
This returns:
(1 row(s) affected)
(1 row(s) affected)
(1 row(s) affected)Msg 2627, Level 14, State 1, Procedure sp_MoveFromTempUpsert_to_Sales, Line 12
Violation of PRIMARY KEY constraint 'PK_Sales'. Cannot insert duplicate key in object
'dbo.Sales'. The statement has been terminated.(1 row(s) affected)
What am I doing wrong please?
Greatly appreciated
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(3)
临时表中的前两行将为您提供重复的 PK。违反。 Conc 是 PK,并且您插入具有相同值的 tmain+dmain 两次。
The first two rows in your staging table will give you the duplicate PK. violation. Conc is the PK and you insert tmain+dmain with the same value twice.
在求和中,
MERGE 要求其输入(使用)不重复
using 是常规 SQL 语句,因此您可以使用 Group By、distinct 和having 以及Where 子句。
我的最终合并看起来像这样:
而且它有效!
谢谢大家:)
In Summation
MERGE requires its input (Using) to be duplicates free
the Using is a regular SQL statement, so you can use Group By, distinct and having as well as Where clauses.
My final Merge looks like so :
And it works!
Thanks to you all :)
如果在 MERGE 的 USING 部分中使用的子查询中没有 DISTINCT 或正确的 AGGREGATE 函数,将会有两行适合 MERGE 的 ON 部分中使用的条件,这是不允许的。 (两个John.Smith)
AND
将条件
src.[Score] = @hashMod
移至子查询内,如果ON子句不成功,例如John.Smith有分数2,并且 @HashMod = 1 - 那么如果目标表中已经有 John.Smith 的行 - 您将收到主键约束错误
Without DISTINCT or proper AGGREGATE function in subquery used in USING part of MERGE there will be two rows which suits criteria used in ON part of MERGE, which is not allowed. (Two John.Smith)
AND
Move the condition
src.[Score] = @hashMod
inside the subquery,instead if ON clause not succeed, for example John.Smith have score of 2, and @HashMod = 1 - then if you already have the row with John.Smith in target table - you'll get an error with Primary Key Constraint