Проблема с производительностью в пункте "Пока"

Ладно всем

Заранее извиняюсь за длину. Это на самом деле довольно весело, хотя.

Я написал сценарий SQL, которым вчера почти гордился, потому что думал, что он довольно умный. Оказывается, это разрушается из-за проблем с производительностью, и я даже не могу проверить это из-за этого, поэтому, возможно, он даже не делает то, о чем я вздыхаю.

Эту проблему лучше всего объяснить на примере:

Колонка А | Колонка Б | Колонка С | Колонка 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. удалить вторую строку после обновления, если было совпадение, и 3. двигаться дальше к следующему ряду, если не было совпадений, и повторите тот же процесс.

Если есть совпадение, обновляется верхняя строка на основе следующего:

  1. Колонка А: ничего
  2. Столбец B: если оба значения одинаковы, оставьте значение в одном, в противном случае напишите "Multiple"
  3. Колонка C: сохранить более раннюю дату между двумя,
  4. Колонка D: сохранить более позднюю дату между двумя,

Затем я удаляю нижний ряд.

Мой пример должен привести к следующему:

Колонка А | Колонка Б | Колонка С | Колонка 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

Чтобы сделать все это, я создал две переменные таблицы, вставил одни и те же данные в обе, а затем перебрал вторую (@ScheduleB) в поисках совпадений, чтобы обновить строку в первой таблице (@ScheduleA). Затем я удалил строку под строкой в ​​@A (потому что она такая же, как B). Наконец, когда совпадений не было, я перешел к следующему ряду в @A, чтобы начать процесс заново. По крайней мере, это то, что код должен делать - см. Ниже.

Проблема в производительности ужасна. Я подумал об использовании курсора, но не знаю, поможет ли там производительность.

Какие-либо предложения?

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's.

1 ответ

Решение

Исходя из ваших требований, я думаю, что подобное решение будет работать:

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 Fiddle

Другие вопросы по тегам