SQL Serverの世界は初めてです。以下の例では、2つの会社があります。
各会社の1つのエントリのみ、列power1, power2, power3
の値があります。
各会社がすべての列の値を持つようにテーブルを更新する必要があります。つまり、すべての空白(null)値を更新する必要があります。
作成したデータの例:
Create Table #Rentarious
(
c1 varchar(200)
,yryryryr datetime
,power1 varchar(200)
,power2 varchar(200)
,power3 varchar(200)
)
Insert Into #Rentarious VALUES
('Building Blocks','2016','Red','Blue','Green')
,('Red Cement', '2012', 'Pink','Purple','Orange')
Insert Into #Rentarious(c1, yryryryr) VALUES
('Building Blocks', '2012')
,('Building Blocks', '2013')
,('Building Blocks', '2014')
,('Red Cement', '2016')
,('Red Cement', '2011')
列power1, power2, power3
のnull値を表に既にリストされている値に更新する更新ステートメントを作成するための構文は何ですか?
各フィールドをコンマで区切ることにより、複数のフィールドをSET
できます。いくつかの一意のパターンに基づいてレコードを指定する必要があります。この場合はc1 and yryryryr
。
UPDATE #Rentarious
SET power1 = 'Red'
, power2 = 'Blue'
, power3 = 'Green'
WHERE c1 = 'Build Blocks'
AND yryryryr = '2012';
構文は、フィールド
power1, power2, power3
のnull値をテーブルに既にリストされている値で更新する更新ステートメントを作成するにはどうすればよいでしょうか。
これは、各企業のnullは、投稿の他の場所で言うように、各企業が持つ1つの入力済みエントリから取得した値に基づいて入力する必要があることを意味します。したがって、疑似コードでは、UPDATEステートメントは次のようにする必要があります。
UPDATE
#Rentarious
SET
power1 = power1 from the same company’s populated row,
power2 = power2 from the same company’s populated row,
power3 = power3 from the same company’s populated row
WHERE power1 IS NULL
AND power2 IS NULL
AND power3 IS NULL
;
上記のパターンを実装する1つの方法は、相関サブクエリを使用することです。
UPDATE
#Rentarious
SET
power1 = (SELECT power1 FROM #Rentarious AS src WHERE src.c1 = #Rentarious.c1 AND src.power1 IS NOT NULL),
power2 = (SELECT power2 FROM #Rentarious AS src WHERE src.c1 = #Rentarious.c1 AND src.power2 IS NOT NULL),
power3 = (SELECT power3 FROM #Rentarious AS src WHERE src.c1 = #Rentarious.c1 AND src.power3 IS NOT NULL)
WHERE power1 IS NULL
AND power2 IS NULL
AND power3 IS NULL
;
これは機能しますが、ソース値を取得するために同じテーブルがさらに3回処理されるため、このような更新はあまり効率的ではない場合があります。 null以外の値は会社ごとに1行に格納されることがわかっているので、派生テーブルと独自の「結合による更新」構文を使用することで、テーブルに対する1回の追加パスですべてを取得できます。
UPDATE
#Rentarious
SET
power1 = sub.power1,
power2 = sub.power2,
power3 = sub.power3
FROM
(
SELECT
c1,
power1,
power2,
power3
FROM
#Rentarious
WHERE power1 IS NOT NULL
AND power2 IS NOT NULL
AND power3 IS NOT NULL
) AS sub
WHERE #Rentarious.c1 = sub.c1
AND #Rentarious.power1 IS NULL
AND #Rentarious.power2 IS NULL
AND #Rentarious.power3 IS NULL
;
明示的なJOIN構文を使用するように書き換えることもできます。
UPDATE
tgt
SET
power1 = src.power1,
power2 = src.power2,
power3 = src.power3
FROM
#Rentarious AS tgt
INNER JOIN
(
SELECT
c1,
power1,
power2,
power3
FROM
#Rentarious
WHERE power1 IS NOT NULL
AND power2 IS NOT NULL
AND power3 IS NOT NULL
) AS sub
ON tgt.c1 = sub.c1
WHERE tgt.power1 IS NULL
AND tgt.power2 IS NULL
AND tgt.power3 IS NULL
;
ご覧のとおり、両方のバリエーションにサブクエリは1つだけあり、3つの値すべてを提供して他の行に入力します。
ただし、余分なスキャンをせずにこの問題を解決することもできます。まず、これがSELECTステートメントである場合、次のように window 集約関数を使用して、すべての行のデータが設定された行の値を返すことができます。
SELECT
c1,
yryryryr,
power1,
power2,
power3,
populatedPower1 = MAX(power1) OVER (PARTITION BY c1),
populatedPower2 = MAX(power2) OVER (PARTITION BY c1),
populatedPower3 = MAX(power3) OVER (PARTITION BY c1)
FROM
#Rentarious
;
[〜#〜] max [〜#〜] 関数は、指定されたセットのnull以外の値全体でのみ最大値を返すため、この状況で機能します。あなたのケースでは、3つのケースのそれぞれでc1
のパーティションごとにnull以外の値が1つしかないため、関数はその1つの値を返します。これはあなたの質問の例のクエリの結果です:
c1 yryryryr power1 power2 power3 populatedPower1 populatedPower2 populatedPower3
--------------- ---------- ------ ------ ------ --------------- --------------- ---------------
Building Blocks 2012-01-01 NULL NULL NULL Red Blue Green
Building Blocks 2013-01-01 NULL NULL NULL Red Blue Green
Building Blocks 2014-01-01 NULL NULL NULL Red Blue Green
Building Blocks 2016-01-01 Red Blue Green Red Blue Green
Red Cement 2012-01-01 Pink Purple Orange Pink Purple Orange
Red Cement 2016-01-01 NULL NULL NULL Pink Purple Orange
Red Cement 2011-01-01 NULL NULL NULL Pink Purple Orange
残っているのは、
SET
power1 = populatedPower1,
power2 = populatedPower2,
power3 = populatedPower3
また、上記のSELECTクエリの結果はUPDATEステートメントのターゲットとして使用できるため、SQL Serverで実際にそれを行うことは可能です。これを派生テーブルとして使用できます。
UPDATE
tgt
SET
power1 = populatedPower1,
power2 = populatedPower2,
power3 = populatedPower3
FROM
(
SELECT
c1,
yryryryr,
power1,
power2,
power3,
populatedPower1 = MAX(power1) OVER (PARTITION BY c1),
populatedPower2 = MAX(power2) OVER (PARTITION BY c1),
populatedPower3 = MAX(power3) OVER (PARTITION BY c1)
FROM
#Rentarious
) AS tgt
WHERE power1 IS NULL
AND power2 IS NULL
AND power3 IS NULL
;
または、CTE( 共通テーブル式 )として実装し、CTEのエイリアスをターゲットとして使用します。
WITH tgt AS
(
SELECT
c1,
yryryryr,
power1,
power2,
power3,
populatedPower1 = MAX(power1) OVER (PARTITION BY c1),
populatedPower2 = MAX(power2) OVER (PARTITION BY c1),
populatedPower3 = MAX(power3) OVER (PARTITION BY c1)
FROM
#Rentarious
)
UPDATE
tgt
SET
power1 = populatedPower1,
power2 = populatedPower2,
power3 = populatedPower3
WHERE power1 IS NULL
AND power2 IS NULL
AND power3 IS NULL
;
どちらも同じように機能し、すべてのnullが対応する値に置き換えられます。つまり、次のようになります。
c1 yryryryr power1 power2 power3
--------------- ---------- ------ ------ ------
Building Blocks 2016-01-01 Red Blue Green
Red Cement 2012-01-01 Pink Purple Orange
Building Blocks 2012-01-01 NULL NULL NULL
Building Blocks 2013-01-01 NULL NULL NULL
Building Blocks 2014-01-01 NULL NULL NULL
Red Cement 2016-01-01 NULL NULL NULL
Red Cement 2011-01-01 NULL NULL NULL
これに:
c1 yryryryr power1 power2 power3
--------------- ---------- ------ ------ ------
Building Blocks 2016-01-01 Red Blue Green
Red Cement 2012-01-01 Pink Purple Orange
Building Blocks 2012-01-01 Red Blue Green
Building Blocks 2013-01-01 Red Blue Green
Building Blocks 2014-01-01 Red Blue Green
Red Cement 2016-01-01 Pink Purple Orange
Red Cement 2011-01-01 Pink Purple Orange
これは、多くの会社がある場合、手動で設定するよりも速くなります。 3または4よりも多くのフィールドがある場合、動的ループを構築することを検討します。
Update R1 Set R1.power1 = R2.power1
From #Rentarious R1
Left Join (Select *
From #Rentarious Where power1 Is Not Null) R2 On R2.C1 = R1.C1
Where R1.power1 Is Null
Update R1 Set R1.power2 = R2.power2
From #Rentarious R1
Left Join (Select *
From #Rentarious Where power2 Is Not Null) R2 On R2.C1 = R1.C1
Where R1.power2 Is Null
Update R1 Set R1.power3 = R2.power3
From #Rentarious R1
Left Join (Select *
From #Rentarious Where power3 Is Not Null) R2 On R2.C1 = R1.C1
Where R1.power3 Is Null