如何在MERGE INTO语句中使用JOIN?

时间:2013-02-07 15:44:13

标签: sql sql-server sql-server-2008 tsql merge

我有三张桌子正在处理注册表格:[月],[会员]和[months_members]。最后一个只是一个连接表。他们看起来像这样:

[months]
========
[id] INT (Primary Key)
[name] VARCHAR(50)
[date] DATE

[members]
=========
[id] INT (Primary Key)
[fname] VARCHAR(50)
[lname] VARCHAR(50)
[email] VARCHAR(300)

[months_members]
================
[id] INT (Primary Key)
[month_id] INT
[member_id] INT

因此,从概念上讲,非常简单。有一个成员列表,他们可以注册几个月。我拥有的表单允许他们注册不同月份,实际上让管理员可以一次性输入(或更改!)所有注册。所以我希望使用MERGE语句通过单个查询将数据导入数据库,而不是迭代多个查询。

所以这就是我开始编写的内容(即使我知道这不是正确的语法):

MERGE INTO [months_members] mm
INNER JOIN [months] mo ON mo.[id] = mm.[month_id] 
USING (
    SELECT 1 AS [month_id], 1 AS [member_id] UNION ALL
    SELECT 2 AS [month_id], 3 AS [member_id] UNION ALL
    SELECT 4 AS [month_id], 4 AS [member_id]
) AS u ON mm.[month_id] = u.[month_id] AND mm.[member_id] = u.[member_id] 
WHEN NOT MATCHED THEN 
    INSERT ([month_id], [member_id]) VALUES (u.[month_id], u.[member_id]) 
WHEN NOT MATCHED BY SOURCE AND DATEPART(YEAR, mo.[start]) = 2013 THEN 
    DELETE;

希望这说明了我遇到的问题。我想将USING子查询中的任何新数据插入[months_members]表。我还希望从[months_members]子查询中 not USING表中删除任何内容 - 但只有当它对应于时才会删除当年的一个月。如果USING子查询中不存在与不同年份对应的数据,我想删除它。我想单独保留这些历史数据。所以DATEPART条件是踢球者。

所以我插入一个表[months_members],但我还需要它知道[months]表。有没有办法实现这个目标?或者我是否必须承认并迭代一些SQL查询?

1 个答案:

答案 0 :(得分:5)

您可以使用CTE代替目标表(或视图)。 SQL Server可以通过CTE /视图跟踪更新。这是一个黑客攻击的演示:

SELECT *
INTO #temp
FROM sys.objects
GO

;WITH cte AS (
    SELECT t1.*
    FROM #temp t1
    JOIN #temp t2 ON t1.object_id = t2.object_id
)
MERGE cte USING (
    SELECT 1 AS [month_id], 1 AS [member_id] UNION ALL
    SELECT 2 AS [month_id], 3 AS [member_id] UNION ALL
    SELECT 4 AS [month_id], 4 AS [member_id]
) AS u ON cte.object_id = u.[month_id]
WHEN MATCHED THEN DELETE;