SQL合并更新问题

时间:2019-04-11 12:15:27

标签: sql-server tsql sql-merge

我试图在执行SQL合并操作时增加项目代码

我有两个桌子。一个拥有很多信息,包括客户和项目。我想将客户名称和项目名称从一个表合并到另一个表。这篇文章很完美,向我展示了如何做我需要做的事情

https://www.mssqltips.com/sqlservertip/1704/using-merge-in-sql-server-to-insert-update-and-delete-at-the-same-time/

但是,我需要维护一个项目编号,该编号在每次添加一条记录时都会递增,并且在您编辑客户或项目名称时不予理会。如果项目被删除,那么我们从下一个可用号码继续。我试图使用分区上的行号来执行此操作,但是它没有给我正确的项目数。

使用文章示例并提供可视化效果,我需要另一列名为Type的食物或饮料作为答案并获得

Item     Cost Code   Type
Tea      10    1     Drink
Coffee   12    2     Drink
Muffin   11    1     Food
Biscuit  4     2     Food

1 个答案:

答案 0 :(得分:1)

我将使用链接提供的示例中的数据,并添加更多数据以确保可以覆盖所有情况,因此首先让我们从这些表开始并填充它们。

--Create a target table
Declare @Products TABLE 
(
   ProductID INT PRIMARY KEY,
   ProductName VARCHAR(100),
   ProductNumber int,
   ProductType VARCHAR(100),
   Rate MONEY
) 

--Insert records into target table
INSERT INTO @Products
VALUES
   (1, 'Tea',       1,'Drink',10.00),
   (2, 'Coffee',    2,'Drink', 20.00),
   (3, 'BiscuitX1', 1,'Food', 45.00) ,
   (4, 'Muffin',    2,'Food', 30.00),
   (5, 'BiscuitX2', 3,'Food', 40.00),
   (6, 'BiscuitX3', 4,'Food', 45.00),
   (7, 'Donut',     5, 'Food', 30.00),
   (8, 'BiscuitX4', 6,'Food', 40.00),
   (9, 'BiscuitX5', 7,'Food', 45.00)  
--Create source table
Declare @UpdatedProducts TABLE 
(
   ProductID INT PRIMARY KEY,
   ProductName VARCHAR(100),
   ProductNumber int,
   ProductType VARCHAR(100),
   Rate MONEY
) 

--Insert records into source table
INSERT INTO @UpdatedProducts
VALUES
   (1, 'Tea',           0,'Drink', 10.00),
   (2, 'Coffee',        0,'Drink', 25.00),
   (4, 'Muffin',        0,'Food', 35.00),
   (7, 'Donut',         0, 'Food', 30.00),
   (10, 'Pizza',        0,'Food', 60.00),
   (11, 'PizzaLarge',   0,'Food', 80.00)

您可以看到我添加了ProductNumber和ProductType。 对于@UpdatedProducts表,我假设您没有产品编号,如果没有,则可以直接合并,如果没有,则需要找到它。

因此,让我们首先更新@UpdatedProducts中的ProductNumber

;with cte as (
    select u.ProductID,u.ProductName,u.ProductType,u.Rate 
    ,coalesce(p.ProductNumber,row_number() over (partition by u.ProductType order by u.ProductID)
    +(select max(pp.ProductNumber) from @Products pp where pp.ProductType=u.ProductType)
    -(select Count(*) from @UpdatedProducts uu 
        inner join @Products ppp on ppp.ProductID=uu.ProductID
        where uu.ProductType=u.ProductType)) [ProductNumber]
    from @UpdatedProducts u
    left outer join @Products p on p.ProductID=u.ProductID
)
update a
    set a.[ProductNumber]=cte.[ProductNumber]
    From @UpdatedProducts a
        inner join cte on cte.ProductID=a.ProductID

我没有找到直接将其放入合并的方法。

更新后@UpdatedProducts的结果如下:-

ProductID   ProductName ProductNumber   ProductType Rate
=========   =========== =============   =========== ====
1           Tea         1               Drink       10.00
2           Coffee      2               Drink       25.00
4           Muffin      2               Food        35.00
7           Donut       5               Food        30.00
10          Pizza       8               Food        60.00
11          PizzaLarge  9               Food        80.00

所以现在我们可以进行直接合并,如下所示:-

--Synchronize the target table with refreshed data from source table
MERGE @Products AS TARGET
USING @UpdatedProducts AS SOURCE 
ON (TARGET.ProductID = SOURCE.ProductID) 
--When records are matched, update the records if there is any change
WHEN MATCHED AND TARGET.ProductName <> SOURCE.ProductName OR TARGET.Rate <> SOURCE.Rate 
    THEN UPDATE SET TARGET.ProductName = SOURCE.ProductName, TARGET.Rate = SOURCE.Rate ,TARGET.ProductNumber= TARGET.ProductNumber --left alone on edit
--When no records are matched, insert the incoming records from source table to target table
WHEN NOT MATCHED BY TARGET 
THEN INSERT (ProductID, ProductName, Rate,ProductNumber,ProductType) 
    VALUES (SOURCE.ProductID, SOURCE.ProductName, SOURCE.Rate,SOURCE.ProductNumber,SOURCE.ProductType)-- increments every time a record is added 
--When there is a row that exists in target and same record does not exist in source then delete this record target
WHEN NOT MATCHED BY SOURCE 
THEN DELETE 
--$action specifies a column of type nvarchar(10) in the OUTPUT clause that returns 
--one of three values for each row: 'INSERT', 'UPDATE', or 'DELETE' according to the action that was performed on that row
OUTPUT $action, 
DELETED.ProductID AS TargetProductID, 
DELETED.ProductName AS TargetProductName, 
DELETED.Rate AS TargetRate, 
INSERTED.ProductID AS SourceProductID, 
INSERTED.ProductName AS SourceProductName, 
INSERTED.Rate AS SourceRate; 


SELECT * FROM @Products

@Products的结果如下:-

ProductID   ProductName ProductNumber   ProductType Rate
=========   =========== =============   =========== ====
1           Tea         1                Drink       10.00
2           Coffee      2                Drink       25.00
4           Muffin      2                Food        35.00
7           Donut       5                Food        30.00
10          Pizza       8                Food        60.00
11          PizzaLarge  9                Food        80.00

对于产品编号(1、3、4、6、7),全部被跳过,新食品Pizza的产品编号为8,而PrizzaLarge的产品编号继续为产品9。 希望这会有所帮助。