web-dev-qa-db-ja.com

SELECT DISTINCTをUPDATE DISTINCTに変更します

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]
    );
4
onmyway

使用できる個別のグループから任意のものを更新するには

_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; 
_

結果の例を以下に示します

enter image description here

_C47474_行は他のテーブルに存在するので除外されるため、_NOT EXISTS_を満たさないでください。残りの行は_Finance_Project_Number_によってグループ化され、各グループ内で連続番号が割り当てられます。

この場合、黄色の行は_RN = 1_条件を満たし、更新されます。ただし、一意であることが保証されている式で_ORDER BY_句を使用しない限り、各グループ内でこれらの番号がどのように割り当てられるかは正確には保証されません。これがないと、同じステートメントの連続した実行間でも変更される可能性があります。

9
Martin Smith

私が他の方法でそれをやろうとしているのと同じくらい、派手な結合などで、私は通常、頭を包み込むのが簡単なものに戻り、さらに、サンプルをテストできます(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の前にセミコロンが必要になる場合があることに注意してください。

  • 私はこのスタイルを実際に見かけないので、おそらくそれほど効率的ではないと思います。私はこれを本番コードの一部にしたり、非常に大きなデータセットで使用したりしません。

0
undrline