Ama*_*mar 3 sql-server stored-procedures sql-merge sql-server-2014
我一直在尝试编写一个存储过程,我可以使用Merge和以下条件执行UpSert
如果记录存在,则将目标的EndDate更改为昨天的日期,即当前日期 - 1
如果Record不存在,则插入新记录
这是我在SP中使用的表tblEmployee
CREATE TABLE tblEmployee
(
[EmployeeID] [int] IDENTITY(1,1) NOT NULL,
[Name] [varchar](10) NOT NULL,
[StartDate] [date] NOT NULL,
[EndDate] [date] NOT NULL
)
Run Code Online (Sandbox Code Playgroud)
这是我的SP,它将UDTT作为输入参数
CREATE PROCEDURE [dbo].[usp_UpsertEmployees]
@typeEmployee typeEmployee READONLY -- It has same column like tblEmployye except EmployeeID
AS
BEGIN
SET NOCOUNT ON;
MERGE INTO tblEmployee AS TARGET
USING @typeEmployee AS SOURCE
ON TARGET.Name = SOURCE.Name
WHEN MATCHED and TARGET.StartDate < SOURCE.StartDate
THEN
--First Update Existing Record EndDate to Previous Date as shown below
UPDATE
set TARGET.EndDate = DATEADD(day, -1, convert(date, SOURCE.StartDate))
-- Now Insert New Record
--INSERT VALUES(SOURCE.Name, SOURCE.StartDate, SOURCE.EndDate);
WHEN NOT MATCHED by TARGET
THEN
INSERT VALUES(SOURCE.Name, SOURCE.StartDate, SOURCE.EndDate);
SET NOCOUNT OFF;
END
Run Code Online (Sandbox Code Playgroud)
如何在匹配列时执行更新现有记录和添加新记录
请有人在TSQL中解释合并的执行流程,即,
WHEN MATCHED --Will this Execute Everytime
WHEN NOT MATCHED by TARGET -- Will this Execute Everytime
WHEN NOT MATCHED by SOURCE -- Will this Execute Everytime
Run Code Online (Sandbox Code Playgroud)
是否所有以上3个条件都在Merge中每次都执行或者每次只执行匹配条件
提前致谢
这不是MERGE意图(在同一条款中更新和插入).要完成此操作,您可以使用该OUTPUT子句仅获取所有更新的记录.该MERGE/ OUTPUT组合是很挑剔的.您的OUTPUT更新实际上是已更新的TARGET记录,因此您必须在temp/table变量中启动TARGET记录.然后你将那些背对着SOURCE进行匹配来进行INSERT.您将不被允许直接将输出结果连接回源,甚至可以用作相关子查询WHERE.
设置一些示例数据
下面的代码只是设置一些示例数据.
-- Setup sample data
DECLARE @typeEmployee TABLE (
[Name] [varchar](10) NOT NULL,
[StartDate] [date] NOT NULL,
[EndDate] [date] NOT NULL
)
DECLARE @tblEmployee TABLE (
[EmployeeID] [int] IDENTITY(1,1) NOT NULL,
[Name] [varchar](10) NOT NULL,
[StartDate] [date] NOT NULL,
[EndDate] [date] NOT NULL
)
INSERT @tblEmployee VALUES ('Emp A', '1/1/2016', '2/1/2016')
INSERT @typeEmployee VALUES ('Emp A', '1/5/2016', '2/2/2016'), ('Emp B', '3/1/2016', '4/1/2016')
Run Code Online (Sandbox Code Playgroud)
存储过程的更新
您可以OUTPUT在a的末尾使用MERGE它来返回目标记录的已修改记录,并通过包含$action,您还将获得它是插入,更新还是删除.
但是,MERGE/ 的结果集OUTPUT不能直接与SOURCE表连接,因此您可以执行自己的操作,INSERT因为您只能获得TARGET记录.您也不能使用OUTPUTSOURCE表中的相关子查询的结果.最简单的方法是使用临时表或表变量来捕获输出.
-- Logic to do upsert
DECLARE @Updates TABLE (
[Name] [varchar](10) NOT NULL,
[StartDate] [date] NOT NULL,
[EndDate] [date] NOT NULL
)
INSERT @Updates
SELECT
Name,
StartDate,
EndDate
FROM (
MERGE INTO @tblEmployee AS TARGET
USING @typeEmployee AS SOURCE
ON TARGET.Name = SOURCE.Name
WHEN MATCHED AND TARGET.StartDate < SOURCE.StartDate
THEN
--First Update Existing Record EndDate to Previous Date as shown below
UPDATE SET
EndDate = DATEADD(DAY, -1, CONVERT(DATE, SOURCE.StartDate))
WHEN NOT MATCHED BY TARGET -- OR MATCHED AND TARGET.StartDate >= SOURCE.StartDate -- Handle this case?
THEN
INSERT VALUES(SOURCE.Name, SOURCE.StartDate, SOURCE.EndDate)
OUTPUT $action, INSERTED.Name, INSERTED.StartDate, INSERTED.EndDate
-- Use the MERGE to return all changed records of target table
) AllChanges (ActionType, Name, StartDate, EndDate)
WHERE AllChanges.ActionType = 'UPDATE' -- Only get records that were updated
Run Code Online (Sandbox Code Playgroud)
现在您已经捕获了MERGE过滤器并将其过滤为仅获取更新的TARGET记录,然后您可以INSERT通过仅过滤作为MERGE更新一部分的SOURCE记录来完成您的未完成记录.
INSERT @tblEmployee
SELECT
SOURCE.Name,
SOURCE.StartDate,
SOURCE.EndDate
FROM @typeEmployee SOURCE
WHERE EXISTS (
SELECT *
FROM @Updates Updates
WHERE Updates.Name = SOURCE.Name
-- Other join conditions to ensure 1:1 match against SOURCE (start date?)
)
Run Code Online (Sandbox Code Playgroud)
输出继电器
这是更改后样本记录的输出.您进行了预期的TARGET更改.
-- Show output
SELECT * FROM @tblEmployee
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
11604 次 |
| 最近记录: |