Sql Server 2008:select子句中低效子查询的替代方法

时间:2013-03-11 12:31:18

标签: sql-server performance sql-server-2008 subquery

我有一张桌子:

SourceID,TargetID,Amount,Year。

我也有一个观点。此视图在同一个表中查看行与其上方行之间的差异。我使用CTE来做到这一点:

    WITH cte as (SELECT ROW_NUMBER() OVER 
(PARTITION BY SourceID ORDER BY ... ) as rowNum, 
SourceId, TargetID, Amount, Year FROM table)

    Select 
    t1.SourceID as SourceID1, 
t2.SourceID as SourceID2, 
t1.TargetID as TargetID1, 
t2.TargetID as TargetID2, 
t1.Year, 
(t1.Amount - t2.Amount) as Difference

    FROM cte t1
    LEFT JOIN cte t2 ON t1.SourceID = t2.SourceID and t1.rowNum = t2.rowNum+1 

我现在在该视图中有2列。 TargetID1和TargetID2。 TargetID2与上面一行中的TargetID1相同。有时TargetID2为null,因为上面显示的左连接中未满足条件。那样就好。从这个视图中选择*正是我需要的。

这里的问题是我想要有条件地选择。例如:我只想选择2012年的行。当然,技术上这不是问题,但是当2012年的第一行与2011年的最后一行(现在看不见)相比时,客户会感到困惑。当它的结果集中的第一行符合连接条件时,它们希望Difference为空(NULL)。

所以我写了这个:

SELECT
    SourceID1, SourceID2, TargetID1, TargetID2, Year,
    case when TargetID2 is null
    then null
    else case when TargetID2 NOT IN (
        select TargetID1 from view where Year = 2012)
    then null
    else Difference
    end
    end as Difference,
FROM view where Year = 2012

这实际上有效...它花了一点时间,因为它是一个相当大的桌子,但它是可以接受的。现在我们添加一个百分比(百分比差异)。这意味着最后一个查询被扩展,另一个条件选择检查完全相同的contion。

case when TargetID2 is null
   then null
   else case when TargetID2 NOT IN (
    select TargetID1 from view where Year = 2012)
   then null
   else Percentage
   end
   end as Percentage

所以这非常消耗。

我的问题是:我该怎么办?通常,对视图或查询的解决方案的更改都很好。只要过滤结果显示第一行的空格为差异和百分比并且查询执行,则没有任何限制。

抱歉这篇大帖子。不知道怎么回事。

由于

编辑:

我对问题不够清楚。如果年份是唯一的问题,我可以做下面的一些建议,但事实并非如此。我简化了表格和视图,因此它更具可读性,但还有其他列和其他东西可以过滤。

还有一个月的专栏。因此,如果我想看到2011年10月 - 2012年的februari,那么2011年的最后一行应该与2012年的第一行进行比较。这里10月的第一行应该具有NULL差异和百分比列,因为TargetID1中不存在TargetID2列...

我希望能够清除它。也许我应该从头开始讨论这个问题。

2 个答案:

答案 0 :(得分:1)

您似乎永远不想将一年的行与前一年的行进行比较。如果是这种情况,您应该在视图中将AND t1.Year = t2.Year添加到连接条件。

如果这是不正确的,并且某种程度上2012年是特殊年份,您可以将t2.Year列添加到视图中。这样你可以直接使用它,而不必加入重新发现它。

答案 1 :(得分:0)

嗯,似乎比我想象的更难解释。我决定使用我之前的解决方案,但是将所有内容放在存储过程中而不是视图+查询中。这样就不必多次迭代同一个表。感谢大家的支持!