我有一张看起来像这样的表:
AccountID, ItemID
1, 100
1, 200
2, 300
我有一个proc,它接受一个表值参数,用于更新与帐户关联的项目。我们将传递以下内容:
AccountID, ItemID
3, 100
3, 200
proc类似于:
procedure dbo.MyProc( @Items as dbo.ItemListTVP READONLY )
AS
BEGIN
MERGE INTO myTable as target
USING @Items
on (Items.AccountId = target.AccountId)
AND (Items.ItemId = target.ItemId)
WHEN NOT MATCHED BY TARGET THEN
INSERT (AccountId, ItemId)
VALUES (Items.AccountId, Items.ItemId)
;
END
根据传入的数据,我希望它能为表格添加2条新记录。
我想要的是有一个WHEN NOT MATCHED BY SOURCE子句,它将删除未匹配的指定帐户的项。
例如,如果我通过
AccountID, ItemID
1, 100
1, 400
然后我希望它删除1,200的记录;但是留下所有其他人。
如果我这样做:
WHEN NOT MATCHED BY SOURCE THEN
DELETE;
然后它将删除未引用的帐户的所有记录(即:帐户ID 2和3)。
我该怎么做?
谢谢,
答案 0 :(得分:41)
我可以想到两种显而易见的方法,但两者都涉及再次处理TVP。
第一种只是改变DELETE
条件
WHEN NOT MATCHED BY SOURCE
AND target.AccountId IN(SELECT AccountId FROM @Items) THEN
DELETE;
第二种是使用CTE来限制目标
WITH cte as
(
SELECT ItemId, AccountId
FROM @myTable m
WHERE EXISTS
(SELECT * FROM @Items i WHERE i.AccountId = m.AccountId)
)
MERGE INTO cte as target
USING @Items Items
ON (Items.AccountId = target.AccountId) AND
(Items.ItemId = target.ItemId)
WHEN NOT MATCHED BY TARGET THEN
INSERT (AccountId, ItemId)
VALUES (Items.AccountId, Items.ItemId)
WHEN NOT MATCHED BY SOURCE THEN
DELETE;
答案 1 :(得分:4)
希望这有帮助。
-- myTable
-- (
-- GroundID bigint, -- FK
-- GroupID, bigint, -- FK
-- AcceptingReservations bit
-- );
merge into myTable as target
using @tmpTable as source
on ( source.GroundID = target.GroundID )
and ( source.GroupID = target.GroupID )
when
not matched by target
then
insert ( GroundID, GroupID, AcceptingReservations )
values
(
source.GroundID,
source.GroupID,
source.AcceptingReservations
)
-- If there is a row that matches, update values;
when matched
then
update set
target.AcceptingReservations = source.AcceptingReservations
-- If they do not match, delete for that GroundID only;
when
not matched by source
and target.GroundID = @GroundID
then
delete;
答案 2 :(得分:2)
在sql数据库中创建表类型变量
CREATE TYPE [dbo].[YourTableType] AS TABLE(
[AccountID] [int] NULL,
[ItemID] [int] NULL
)
GO
在更新程序中进行更改
ALTER PROCEDURE YourProcedure
@Items YourTableType READONLY
AS
BEGIN
MERGE INTO [dbo].[YourTable] as Target
USING @Items as Source
ON
Target.[AccountID]=Source.[AccountID] and
Target.[ItemID]=Source.[ItemID]
WHEN NOT MATCHED by TARGET THEN
INSERT
([AccountID],
[ItemID])
VALUES
(Source.[AccountID],
Source.[ItemID])
WHEN NOT MATCHED BY SOURCE AND
target.[ItemID] IN(SELECT [ItemID] FROM @Items)
THEN
DELETE;
END
答案 3 :(得分:0)
上述答案适用于所描述的情况。
我有一个异常表,用于存储发票的例外情况。我只希望它包含发票的当前例外情况。因此,如果我在发票数据中修复了一些内容并再次运行该过程,则会创建一个新的异常列表。我希望它添加新的例外,更新现有的例外,并删除不再存在的例外 - 因为它们属于同一发明(或其他)。
我遇到的问题是MERGE语句如果没有与源匹配那么删除会删除TARGET表中的所有内容;不只是在SOURCE中不再有额外的物品了!我无法限定WHEN NOT MATCHED BY SOURCE语句,因此DELETE只会影响TARGET中不再在SOURCE中的相同发票号。
错误告诉我“在MERGE声明的'WHEN NOT MATCHED BY SOURCE'子句中只允许使用目标列。”
因此,您必须使用变量限定TARGET行。