ID ごとに 1 つのキー 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 関数を使用して、グループごと (この場合は ID ごと) の最大値を決定しますdate2
。これが元のデータセットの場合:
╔═══════════════════════════════╗
║ 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 ごとに複数のキー 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 ║
╚═════════════════════════════════════════╝
次に、メソッドを適用します。
このような基準を追加する 1 つの方法は、次のクエリのように、条件付き実行カウントを使用することです。
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 行でのみ増加し、他の行では同じままです。CTEはpartitions
、ID パーティションごとに独立した実行カウントを取得します。その結果、前に示したように rangeID 値を取得します。
maxdates
CTEpartitions
は rangeID 値の結果を読み取り、先ほど説明した追加の基準として使用します。2 番目のクエリの残りの部分は、最初のクエリのロジックに従います。
この方法のライブ デモは、SQL Fiddle にあります。
参考になる関連マニュアルページ: