1

では皆さん、

長文をあらかじめお詫び申し上げます。これは実際にはちょっと楽しいです。

私は SQL スクリプトを作成しましたが、それは非常に賢いと思ったので、昨日は半ば誇りに思っていました。パフォーマンスの問題で台無しになることが判明し、そのためにテストすることさえできないので、ため息をつくと思うことさえしていない可能性があります。

この問題は、次の例で最もよく説明されています。

列 A | 列 B | C列 | D列

   Heart   |      K      |  2/1/2013  |   3/1/2013
   Heart   |      K      |  2/1/2013  |   3/1/2013
   Heart   |      K      |  1/1/2013  |   3/1/2013
   Heart   |      K      |  2/1/2013  |   4/1/2013
   Spade   |      4      |  2/1/2013  |   3/1/2013
   Spade   |      3      |  2/1/2013  |   3/1/2013
   Club    |      4      |  2/1/2013  |   3/1/2013

このテーブルでは、次のことを行う必要があります。1.最初の行から始めて、列 A の値が一致する場合は、それに続くデータで行を更新します。2.一致した場合は、更新後に 2 番目の行を削除します。3.次に進みます。一致しなかった場合は次の行に進み、同じプロセスを再実行します。

一致する場合は、以下に基づいて上位の行が更新されます。

  1. A列:なし
  2. 列 B: 両方の値が同じ場合は一方の値のまま、そうでない場合は「複数」と記入
  3. 列 C: 2 つの間の早い方の日付を保持し、
  4. 列 D: 2 つの間の後の日付を保持し、

次に、下の行を削除します。

私の例は次のようになります。

列 A | 列 B | C列 | D列

   Heart   |      K      |  1/1/2013  |  4/1/2013
   Spade   |   Multiple  |  2/1/2013  |   3/1/2013
   Club    |      4      |  2/1/2013  |   3/1/2013

これをすべて行うために、2 つのテーブル変数を作成し、両方に同じデータを挿入し、2 番目 (@ScheduleB) を循環して一致を探し、最初のテーブル (@ScheduleA) の行を更新します。次に、@A の行の下の行を削除しました (B と同じであるため)。最後に、一致するものがない場合、@A の次の行に移動してプロセスを最初からやり直しました。少なくとも、それがコードの本来の目的です。以下を参照してください。

問題は、パフォーマンスがひどいことです。Cursor の使用を検討しましたが、パフォーマンスが役立つかどうかはわかりません。

助言がありますか?

Declare @ScheduleA Table
(
    RowNumber int,
    Period nvarchar(MAX),
    Program nvarchar(MAX),
    ControlAccount Nchar(50),
    WorkPackage Nchar(50),
    CAM Nchar(50),
    EVM Nchar(50),
    Duration int,
    BLStart datetime,
    BLFinish datetime
)

Declare @ScheduleB Table
    (
        RowNumber int,
        Period nvarchar(MAX),
        Program nvarchar(MAX),
        ControlAccount Nchar(50),
        WorkPackage Nchar(50),
        CAM Nchar(50),
        EVM Nchar(50),
        Duration int,
        BLStart datetime,
        BLFinish datetime
    )

Insert INTO @ScheduleA
Select ROW_NUMBER() OVER(order by workpackage desc) as [Row], Period, Program,       
ControlAccount, WorkPackage, CAM, EVM, Duration, BLStart, BLFinish
From ScheduleData 
where program = @Program and period = @Period

Insert INTO @ScheduleB
Select ROW_NUMBER() OVER(order by workpackage desc) as [Row], Period, Program,   
ControlAccount, WorkPackage, CAM, EVM, Duration, BLStart, BLFinish
From ScheduleData 
where program = @Program and period = @Period

declare @i int = 1
declare @j int = 2

--Create a loop for the second variable that counts up to the last row of the B table
While @j < (select MAX(ROWNUMBER) + 1 from @ScheduleB)
Begin
--if the tables match by WorkPackage THEN
IF ((select WorkPackage from @ScheduleA where RowNumber = @i) = 
    (select workpackage from @ScheduleB where RowNumber = @j))
    Begin 
        Update @ScheduleA 
 --Update the Schedule CAM, BLStart, BLFinish of     the A table (if necessary)
set CAM = 
    Case
               --Set values in @ScheduleA Column B based on logic
        End,

BLStart = 
        Case
               --Set values in @ScheduleA Column C  based on logic
    End,

BLFinish = 
    Case
               --Set values in @ScheduleA Column D based on logic
            End
    Where RowNumber = @i

Delete from @ScheduleA 
where RowNumber = @i + 1

set @j = @j + 1 --next row in B
End
ELSE 
set @i = @i + 1
END

編集: 明確にするために、列 B は整数列ではありません。カードは非常に簡単に理解できるため、これを例として使用しただけです。それ以来、K を含めるようにコラムを更新しました。

4

1 に答える 1

3

あなたの要件に基づいて、私はこのような解決策がうまくいくと思います:

SELECT 
    [column a], 
    CASE WHEN MAX([column b]) <> MIN([column b]) THEN 'multiple' ELSE CAST(MAX([column b]) AS NVARCHAR(10)) END,
    MIN([column c]), 
    MAX([column d]) 
FROM Table
GROUP BY [column a]

編集:

SQL フィドル

于 2013-06-20T19:23:24.330 に答える