SELECT DISTINCT
クエリをUPDATE DISTINCT
クエリに変更するにはどうすればよいですか?
各[Finance_Project_Number]には複数のレコードが関連付けられているため(CRUD操作のため)、個別のレコードのみを更新することが重要です。データを検証する別のプロセスを開始するだけなので、1つのレコードのみを更新します。
DISTINCTの結果として複数のレコードが1つの行に折りたたまれている場合、これらのいずれかを更新できます。これは重要ではありません。
選択クエリを実行すると、次の結果が得られます。6 982:
SELECT DISTINCT
[Finance_Project_Number]
FROM [InterfaceInfor].[dbo].[ProjectMaster]
WHERE
NOT EXISTS
(
SELECT *
FROM [IMS].[dbo].[THEOPTION]
WHERE
[InterfaceInfor].[dbo].[ProjectMaster].[Finance_Project_Number] =
[IMS].[dbo].[THEOPTION].[NAME]
);
これが私のクエリをDISTINCT UPDATE
クエリに変換しようとする試みですが、これにより15 353レコードが更新されます。
UPDATE [InterfaceInfor].[dbo].[ProjectMaster]
SET
[Processing_Result_Text] = 'UNIQUE',
[Processing_Result] = 0
WHERE
NOT EXISTS
(
SELECT *
FROM [IMS].[dbo].[THEOPTION]
WHERE
[InterfaceInfor].[dbo].[ProjectMaster].[Finance_Project_Number] =
[IMS].[dbo].[THEOPTION].[NAME]
);
使用できる個別のグループから任意のものを更新するには
_WITH T
AS (SELECT ROW_NUMBER() OVER (PARTITION BY [Finance_Project_Number]
ORDER BY (SELECT 0)) AS RN,
[Processing_Result_Text],
[Processing_Result]
FROM [InterfaceInfor].[dbo].[ProjectMaster]
WHERE NOT EXISTS (SELECT *
FROM [IMS].[dbo].[THEOPTION]
WHERE [InterfaceInfor].[dbo].[ProjectMaster].[Finance_Project_Number] = [IMS].[dbo].[THEOPTION].[NAME]))
UPDATE T
SET [Processing_Result_Text] = 'UNIQUE',
[Processing_Result] = 0
WHERE RN = 1;
_
更新する行を選択するための基準があると判断した場合は、結局ORDER BY (SELECT 0)
を適宜変更して、目的のターゲット行が最初に順序付けられるようにします。 _ORDER BY DateInserted desc
_は、DateInsertedという列が存在する場合、その列によって順序付けられた最新の列を更新します。
_ROW_NUMBER
_ などのランキング関数をWHERE
句で直接参照することは許可されていないため、これは 共通テーブル式 (CTE)を使用します。 更新可能なビュー と同じ状況で、共通テーブル式を介してデータを更新できます(基本的に、更新されるデータは、単一のベーステーブル内の特定のアイテムに直接直接マップできる必要があります)。
ランキング関数にまだ慣れていない場合は、最初にCTEのSELECT
- ingが有益であることがわかります。
_CREATE TABLE #TheOption(NAME VARCHAR(50));
CREATE TABLE #ProjectMaster
(
Finance_Project_Number VARCHAR(10) NOT NULL,
Processing_Result_Text VARCHAR(50) NULL,
Processing_Result INT NULL
);
INSERT INTO #ProjectMaster (Finance_Project_Number, Processing_Result_Text)
VALUES ('A00001', 'A'),
('A00001', 'B'),
('A00001', 'C'),
('B99999', 'D'),
('B99999', 'E'),
('C47474', 'F'),
('C47474', 'G');
INSERT INTO #TheOption (NAME) VALUES('C47474');
WITH T
AS (SELECT ROW_NUMBER() OVER (PARTITION BY Finance_Project_Number
ORDER BY (SELECT 0)) AS RN,
Finance_Project_Number,
Processing_Result_Text,
Processing_Result
FROM #ProjectMaster pm
WHERE NOT EXISTS (SELECT *
FROM #TheOption opt
WHERE pm.Finance_Project_Number =opt.NAME))
SELECT *
FROM T
ORDER BY Finance_Project_Number, RN;
_
結果の例を以下に示します
_C47474
_行は他のテーブルに存在するので除外されるため、_NOT EXISTS
_を満たさないでください。残りの行は_Finance_Project_Number
_によってグループ化され、各グループ内で連続番号が割り当てられます。
この場合、黄色の行は_RN = 1
_条件を満たし、更新されます。ただし、一意であることが保証されている式で_ORDER BY
_句を使用しない限り、各グループ内でこれらの番号がどのように割り当てられるかは正確には保証されません。これがないと、同じステートメントの連続した実行間でも変更される可能性があります。
私が他の方法でそれをやろうとしているのと同じくらい、派手な結合などで、私は通常、頭を包み込むのが簡単なものに戻り、さらに、サンプルをテストできます(UPDATE/SET
を実行する前にSELECT
)を付けます。
WITH UpdateData AS (
SELECT DISTINCT t.match, t.oldvalue, t2.newvalue
FROM Origin t
JOIN newstuff t2 ON t.PK = t2.FK
WHERE t.Valid = 1 AND t2.Valid = 1
)
UPDATE Origin
SET Origin.oldvalue=UpdateData.newvalue
FROM Origin
INNER JOIN UpdateData
ON UpdateData.match=Origin.match
WHERE Origin.Valid = 1
いくつかの警告:
これを大きなスクリプトの一部として実行する場合は、WITH
の前にセミコロンが必要になる場合があることに注意してください。
私はこのスタイルを実際に見かけないので、おそらくそれほど効率的ではないと思います。私はこれを本番コードの一部にしたり、非常に大きなデータセットで使用したりしません。