合并语句在源表中更改姓氏后给出错误

时间:2016-12-17 04:35:46

标签: sql tsql sql-server-2016

我在登台数据库中有一个名为payroll的源表。我正在使用Merge语句将员工数据从Staging插入到Expense数据库。一旦员工结婚并更改了他们的姓氏,我就会收到此错误:

  

MERGE语句尝试多次更新或删除同一行。当目标行与多个源行匹配时会发生这种情况。 MERGE语句不能多次更新/删除目标表的同一行。优化ON子句以确保目标行最多匹配一个源行,或使用GROUP BY子句对源行进行分组。

我在EmployeeID表格中的Employee上有一个唯一索引。举个例子,我得到一个文件,其唯一身份证号为10072,名字为Abby,姓氏为史密斯,一旦艾比结婚,她的姓氏将更改为马歇尔,但姓名和员工身份相同。我该怎么办?

这是我的合并声明。

MERGE INTO Dimension.Employee AS T
        USING 
            (
                SELECT DISTINCT 
                    LTRIM(RTRIM(EmplID)) AS EmployeeID
                    ,LTRIM(RTRIM(FirstName)) AS FirstName
                    ,LTRIM(RTRIM(LastName)) AS LastName
                FROM Staging.PayRoll
            ) AS S
            ON T.EmployeeID = S.EmployeeID
                WHEN NOT MATCHED THEN 
                    INSERT (EmployeeID, FirstName, LastName)
                    VALUES (S.EmployeeID, S.FirstName, S.LastName)
                WHEN MATCHED THEN UPDATE SET
                    T.FirstName = S.FirstName
                    , T.LastName = S.LastName
                    ;

1 个答案:

答案 0 :(得分:1)

听起来这段代码为同一个ID生成了2行,当名称更改时,Payroll表有2个EmpID。

            SELECT DISTINCT 
                LTRIM(RTRIM(EmplID)) AS EmployeeID
                ,LTRIM(RTRIM(FirstName)) AS FirstName
                ,LTRIM(RTRIM(LastName)) AS LastName
            FROM Staging.PayRoll

然后,merge语句尝试两次更新Target表中的同一行。 理论上你不能这样做,因为SQL可以在任何ORDER中返回数据,因此你不能以正确的顺序应用你的2个更新。

以下是错误和可能解决方案的示例。 (对不起,我没有足够的关于工资表的信息来提供更多信息)

DROP TABLE #Payroll
CREATE TABLE #Payroll (ID INT
                    ,EmplID INT
                    ,Name VARCHAR(10)
                    )

INSERT INTO #Payroll VALUES
(1,10,'Bill')
,(2,10,'Bill')
,(3,20,'John')
,(4,20,'John')
,(5,30,'Stephen')
,(6,30,'Steven') --EmpID 30 changes his name

--Steven changed name, but the query is generating a duplicate the MERGE will not be happy
SELECT DISTINCT 
    LTRIM(RTRIM(EmplID)) AS EmployeeID
    ,LTRIM(RTRIM(Name)) AS FirstName
FROM #Payroll

--Solution
SELECT DISTINCT 
    LTRIM(RTRIM(P.EmplID)) AS EmployeeID
    ,LTRIM(RTRIM(P.Name)) AS FirstName
FROM #Payroll P
    CROSS APPLY (SELECT TOP 1 * FROM #Payroll T
                WHERE T.EmplID = P.EmplID 
                ORDER BY ID DESC) L
WHERE
    L.ID = P.ID