如果每个 ID 有一个键 1 行,并且所有现有的具有相同 ID 值的键 8 行都与之相关,您可以尝试以下方法:
WITH maxdates AS (
SELECT
*,
maxdate2 = MAX(CASE [key] WHEN 8 THEN date2 END) OVER (PARTITION BY ID)
FROM dbo.atable
)
UPDATE maxdates
SET date2 = maxdate2
WHERE [key] = 1
AND maxdate2 IS NOT NULL
;
这就是它的工作原理。公用表maxdates
表达式使用窗口 MAX 函数来确定date2
每个组(在本例中为每个 ID)的最大值。如果这是原始数据集:
╔═══════════════════════════════╗
║ ID date1 date2 key ║
╠═══════════════════════════════╣
║ 1 1/2/2014 5/2/2014 1 ║
║ 1 5/2/2014 8/2/2014 8 ║
║ 1 8/2/2014 9/2/2014 8 ║
║ 2 12/2/2014 14/2/2014 1 ║
║ 2 14/2/2014 17/2/2014 8 ║
║ 3 20/2/2014 23/2/2014 1 ║
╚═══════════════════════════════╝
CTE 会将其变成以下内容:
╔══════════════════════════════════════════╗
║ ID date1 date2 key maxdate2 ║
╠══════════════════════════════════════════╣
║ 1 1/2/2014 5/2/2014 1 9/2/2014 ║
║ 1 5/2/2014 8/2/2014 8 9/2/2014 ║
║ 1 8/2/2014 9/2/2014 8 9/2/2014 ║
║ 2 12/2/2014 14/2/2014 1 17/2/2014 ║
║ 2 14/2/2014 17/2/2014 8 17/2/2014 ║
║ 3 20/2/2014 23/2/2014 1 NULL ║
╚══════════════════════════════════════════╝
UPDATE 语句将首先过滤掉不被更新的行,即那些key
为 8 的行以及没有关联键 8 行的键 1 行(通过缺席确定它们maxdate2
),从而产生以下子集:
╔══════════════════════════════════════════╗
║ ID date1 date2 key maxdate2 ║
╠══════════════════════════════════════════╣
║ 1 1/2/2014 5/2/2014 1 9/2/2014 ║
║ 2 12/2/2014 14/2/2014 1 17/2/2014 ║
╚══════════════════════════════════════════╝
然后更新date2
为maxdate2
.
现在,即使每个 ID 允许多个 key 1 行,此方法仍然适用。您只需要提出另一个标准来识别同一 ID 组中相关行的子组。也就是说,您首先需要像这样转换数据集:
╔═══════════════════════════════╗
║ ID date1 date2 key ║
╠═══════════════════════════════╣
║ 1 1/2/2014 5/2/2014 1 ║
║ 1 5/2/2014 8/2/2014 8 ║
║ 1 8/2/2014 9/2/2014 8 ║
║ 1 12/2/2014 14/2/2014 1 ║
║ 1 14/2/2014 17/2/2014 8 ║
║ 1 20/2/2014 23/2/2014 1 ║
╚═══════════════════════════════╝
变成这样的东西:
╔═════════════════════════════════════════╗
║ ID date1 date2 key rangeID ║
╠═════════════════════════════════════════╣
║ 1 1/2/2014 5/2/2014 1 1 ║
║ 1 5/2/2014 8/2/2014 8 1 ║
║ 1 8/2/2014 9/2/2014 8 1 ║
║ 1 12/2/2014 14/2/2014 1 2 ║
║ 1 14/2/2014 17/2/2014 8 2 ║
║ 1 20/2/2014 23/2/2014 1 3 ║
╚═════════════════════════════════════════╝
然后应用该方法。
添加此类标准的一种方法是使用有条件的运行计数,如以下查询:
WITH partitions AS (
SELECT
*,
rangeID = COUNT(CASE [key] WHEN 1 THEN 1 END) OVER (PARTITION BY ID ORDER BY date1)
FROM dbo.atable
),
maxdates AS (
SELECT
*,
maxdate2 = MAX(CASE [key] WHEN 8 THEN date2 END) OVER (PARTITION BY ID, rangeID)
FROM partitions
)
UPDATE maxdates
SET date2 = maxdate2
WHERE [key] = 1
AND maxdate2 IS NOT NULL
;
基本上,COUNT() OVER (... ORDER BY ...)
是一个运行计数,CASE 表达式使其成为有条件的:计数仅在关键 1 行上增加,而在其他行上保持不变。partitions
CTE 获取每个 ID 分区的独立运行计数。结果,您将获得如前所述的 rangeID 值。
maxdates
CTE 读取结果并将partitions
rangeID 值用作我所说的附加标准。第二个查询的其余部分遵循第一个查询的逻辑。
可以在 SQL Fiddle找到此方法的现场演示。
可能有用的相关手册页: