T-SQL :合并插入旧值和新值然后进行更改
T-SQL : merge insert old and new value then make changes
这是我第一次使用 T-SQL Merge
,我一直在尝试使用以下条件编写存储过程:
如果存在记录,则将 Id、旧值(更新前)和新值插入 Changes
table,然后从 [= 更新旧值15=]
如果记录不存在,则将 Id 插入 Changes
,旧值和新值均为空,然后在 Affected
中插入新记录
如果记录不匹配,则将 Id、旧值(删除前的值)和空值插入 Changes
中作为新值,然后删除记录
这是我用过的 table
CREATE TABLE Affected
(
[Id] int IDENTITY(1,1) NOT NULL,
[ZoneId] int NOT NULL,
[Name] varchar(100) NOT NULL,
[Value] varchar(100)
)
CREATE TABLE Changes
(
[AffectedId] int NOT NULL,
[OldValue] varchar(100),
[NewValue] varchar(100)
)
这是我的存储过程,它将两个区域 ID 作为输入参数
CREATE PROCEDURE spAffectChanges
@ZoneId1 int,
@ZoneId2 int
AS
IF(@ZoneId1 < 10)
BEGIN
;WITH fromQ AS
(
SELECT DISTINCT Name, Value
FROM Affected
WHERE ZoneId = @ZoneId1 AND Name NOT IN ('aaa', 'bbb', 'ccc')
), toQ AS
(
SELECT DISTINCT Name, Value
FROM Affected
WHERE ZoneId = @ZoneId2 AND Name NOT IN ('aaa', 'bbb', 'ccc')
)
MERGE toQ
USING fromQ ON (toQ.Name = fromQ.Name)
WHEN MATCHED AND fromQ.Value<>toQ.Value THEN
----first insert
INSERT INTO Changes (AffectedId, OldValue, NewValue)
VALUES(toQ.Id, toQ.Value, fromQ.Value)
----then update
UPDATE SET toQ.Value=fromQ.Value
WHEN NOT MATCHED BY toQ THEN
----first insert
INSERT INTO Changes (AffectedId, OldValue, NewValue)
VALUES(toQ.Id, '', fromQ.Value)
----second insert
INSERT (Name, Zone, Value)
VALUES (fromQ.Name, @ZoneId1, fromQ.Value)
WHEN NOT MATCHED BY fromQ THEN
----first insert
INSERT INTO Changes (AffectedId, OldValue, NewValue)
VALUES(toQ.Id, toQ.Value, '')
----then delete
DELETE
END
有没有办法对 Affected
执行插入更改和 Update/Insert/Delete?
提前致谢
您可以使用 OUTPUT
子句来执行此操作。
备注:
MERGE
需要 分号终止符。 ;WITH
很傻,;
不是开始符,它应该放在每个命令的末尾
WHEN NOT MATCHED
的选项是 BY SOURCE
和 BY TARGET
(这是默认值)
- 我不太明白你如何在目标上设置
DISTINCT
,我不认为这是允许的,也不认为这样做有什么意义。
WITH fromQ AS
(
SELECT DISTINCT Name, Value
FROM Affected
WHERE ZoneId = @ZoneId1 AND Name NOT IN ('aaa', 'bbb', 'ccc')
), toQ AS
(
SELECT Name, Value
FROM Affected
WHERE ZoneId = @ZoneId2 AND Name NOT IN ('aaa', 'bbb', 'ccc')
)
MERGE toQ
USING fromQ ON (toQ.Name = fromQ.Name)
WHEN MATCHED AND fromQ.Value <> toQ.Value THEN
UPDATE
SET toQ.Value = fromQ.Value
WHEN NOT MATCHED BY TARGET THEN
INSERT (Name, Zone, Value)
VALUES (fromQ.Name, @ZoneId1, fromQ.Value)
WHEN NOT MATCHED BY SOURCE THEN
DELETE
OUTPUT inserted.Id, ISNULL(deleted.Value, ''), ISNULL(inserted.Value, '')
INTO Changes (AffectedId, OldValue, NewValue)
;
这是我第一次使用 T-SQL Merge
,我一直在尝试使用以下条件编写存储过程:
如果存在记录,则将 Id、旧值(更新前)和新值插入
Changes
table,然后从 [= 更新旧值15=]如果记录不存在,则将 Id 插入
中插入新记录Changes
,旧值和新值均为空,然后在Affected
如果记录不匹配,则将 Id、旧值(删除前的值)和空值插入
Changes
中作为新值,然后删除记录
这是我用过的 table
CREATE TABLE Affected
(
[Id] int IDENTITY(1,1) NOT NULL,
[ZoneId] int NOT NULL,
[Name] varchar(100) NOT NULL,
[Value] varchar(100)
)
CREATE TABLE Changes
(
[AffectedId] int NOT NULL,
[OldValue] varchar(100),
[NewValue] varchar(100)
)
这是我的存储过程,它将两个区域 ID 作为输入参数
CREATE PROCEDURE spAffectChanges
@ZoneId1 int,
@ZoneId2 int
AS
IF(@ZoneId1 < 10)
BEGIN
;WITH fromQ AS
(
SELECT DISTINCT Name, Value
FROM Affected
WHERE ZoneId = @ZoneId1 AND Name NOT IN ('aaa', 'bbb', 'ccc')
), toQ AS
(
SELECT DISTINCT Name, Value
FROM Affected
WHERE ZoneId = @ZoneId2 AND Name NOT IN ('aaa', 'bbb', 'ccc')
)
MERGE toQ
USING fromQ ON (toQ.Name = fromQ.Name)
WHEN MATCHED AND fromQ.Value<>toQ.Value THEN
----first insert
INSERT INTO Changes (AffectedId, OldValue, NewValue)
VALUES(toQ.Id, toQ.Value, fromQ.Value)
----then update
UPDATE SET toQ.Value=fromQ.Value
WHEN NOT MATCHED BY toQ THEN
----first insert
INSERT INTO Changes (AffectedId, OldValue, NewValue)
VALUES(toQ.Id, '', fromQ.Value)
----second insert
INSERT (Name, Zone, Value)
VALUES (fromQ.Name, @ZoneId1, fromQ.Value)
WHEN NOT MATCHED BY fromQ THEN
----first insert
INSERT INTO Changes (AffectedId, OldValue, NewValue)
VALUES(toQ.Id, toQ.Value, '')
----then delete
DELETE
END
有没有办法对 Affected
执行插入更改和 Update/Insert/Delete?
提前致谢
您可以使用 OUTPUT
子句来执行此操作。
备注:
MERGE
需要 分号终止符。;WITH
很傻,;
不是开始符,它应该放在每个命令的末尾WHEN NOT MATCHED
的选项是BY SOURCE
和BY TARGET
(这是默认值)- 我不太明白你如何在目标上设置
DISTINCT
,我不认为这是允许的,也不认为这样做有什么意义。
WITH fromQ AS
(
SELECT DISTINCT Name, Value
FROM Affected
WHERE ZoneId = @ZoneId1 AND Name NOT IN ('aaa', 'bbb', 'ccc')
), toQ AS
(
SELECT Name, Value
FROM Affected
WHERE ZoneId = @ZoneId2 AND Name NOT IN ('aaa', 'bbb', 'ccc')
)
MERGE toQ
USING fromQ ON (toQ.Name = fromQ.Name)
WHEN MATCHED AND fromQ.Value <> toQ.Value THEN
UPDATE
SET toQ.Value = fromQ.Value
WHEN NOT MATCHED BY TARGET THEN
INSERT (Name, Zone, Value)
VALUES (fromQ.Name, @ZoneId1, fromQ.Value)
WHEN NOT MATCHED BY SOURCE THEN
DELETE
OUTPUT inserted.Id, ISNULL(deleted.Value, ''), ISNULL(inserted.Value, '')
INTO Changes (AffectedId, OldValue, NewValue)
;