1

大家好,

提前为篇幅道歉。不过,这实际上很有趣。

昨天我写了一个让我半自豪的 SQL 脚本,因为我认为它非常聪明。结果它被性能问题毁了,因此我什至无法测试它,所以它甚至可能没有做我认为的sigh

这个问题最好用一个例子来解释:

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. 如果匹配,则在更新后删除第二行,以及 3. 继续如果没有匹配到下一行并重新运行相同的过程。

如果匹配,则较高的行将根据以下内容进行更新:

  1. A栏:无
  2. B 列:如果两个值相同,则将值合二为一,否则写“多个”
  3. C列:保持两者之间较早的日期,
  4. D列:保留两者之间的较晚日期,

然后我删除下一行。

我的示例应导致以下结果:

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

为此,我创建了两个表变量,将相同的数据插入到两者中,然后循环通过第二个 (@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。

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 回答