Tsql 什么';这个T-SQL合并语句有什么问题?

Tsql 什么';这个T-SQL合并语句有什么问题?,tsql,merge,upsert,Tsql,Merge,Upsert,我是新来的合并,我确信我的代码中有一些错误 此代码将运行并创建我的场景: 我有两个表,一个叫做tempuspert,它通过SqlBulkCopy操作(100个百万记录)填充,另一个叫做Sales表,它保存要索引和使用的生产数据 我希望将tempuspert表与Sales表合并 我显然做错了什么,因为即使是最小的例子也失败了 IF EXISTS (SELECT * FROM sys.objects WHERE object_id = OBJECT_ID(N'[dbo].[TempUpsert]'

我是新来的
合并
,我确信我的代码中有一些错误

此代码将运行并创建我的场景:

我有两个表,一个叫做
tempuspert
,它通过
SqlBulkCopy
操作(100个百万记录)填充,另一个叫做
Sales
表,它保存要索引和使用的生产数据

我希望将
tempuspert
表与
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行受影响)

Msg 2627,第14级,状态1,程序sp_从临时插入移动到销售,第12行
违反主键约束“主键销售”。无法在对象中插入重复的键 “dbo.Sales”。声明已终止

(1行受影响)

请问我做错了什么


非常感谢

您的暂存表的前两行将为您提供重复的PK。违反Conc是主键,您可以使用相同的值插入两次tmain+dmain。

如果在使用合并部分时使用的子查询中没有明确或正确的聚合函数,则将有两行符合合并部分中使用的条件,这是不允许的。(两个约翰·史密斯)

将条件
src.[Score]=@hashMod
移动到子查询中

相反,如果ON子句不成功,例如John.Smith的分数为2,@HashMod=1,那么如果目标表中已经有John.Smith所在的行,那么在求和中会出现主键约束错误

合并要求其输入(使用)是无重复的 Using是一个常规SQL语句,因此您可以使用GROUPBY、distinct和having以及Where子句

我的最终合并看起来是这样的:

MERGE Sales AS trget
    USING (

    SELECT     FirstName, LastName, Score, LastName + '.' + FirstName AS FullName
    FROM         TempUpsert AS ups
    WHERE Score = @hashMod  
    GROUP BY FirstName, LastName, Score, LastName + '.' + FirstName

    ) 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
而且它有效


谢谢大家:)

嗨,米卡尔,谢谢你们的快速回复。我在staging表中有1000条重复记录,这就是我使用合并的原因statement@MickeyPerlstein合并将只匹配目标表中已有的重复项。不是在执行时。您必须使用子句删除
中的重复项。对不起,我该怎么做?分组?不同的?你可以按名字和姓氏分组。您需要对分数使用聚合函数。(max,min…)OMG,我一直运行脚本,它删除了表,因此总是插入。谢谢:)不匹配时的
等在任何插入发生之前进行评估,如果这是混淆的根源?这并不是说,一旦插入匹配行,则具有相同主键的未来行将被视为
匹配的
。这是万圣节保护所必需的。当匹配发生时,我希望更新[lastupdated]字段,当匹配失败时,我希望在Sales表中插入新记录。我不能从暂存表(tempuspert)中选择我的输入。谢谢Oleg,在这个关头我理解这一点。我目前的问题是,merge现在是一个复杂的插入系统,但它永远不会只更新INSERTSSee您在@hashMod中提供了什么