SQL在比较连续DataRows中的值时使用PARTITION

时间:2013-02-07 15:52:27

标签: sql

我正在使用SQL语句来比较字段[Allocation]的连续值,如下所示:

;WITH cteMain AS
(SELECT AllocID, CaseNo, FeeEarner, Allocation, ROW_NUMBER() OVER (ORDER BY AllocID) AS sn
FROM tblAllocations)

SELECT m.AllocID, m.CaseNo, m.FeeEarner, m.Allocation, 
       ISNULL(sLag.Allocation, 0) AS prevAllocation,
      (m.Allocation - ISNULL(sLag.Allocation, 0)) AS movement
FROM cteMain AS m

LEFT OUTER JOIN cteMain AS sLag
ON sLag.sn = m.sn-1;

查询返回计算字段[移动],即[分配]的连续值的增加或减少。

我已经包含了此查询返回的数据的屏幕截图。

Screenshot of returned data

但是查询尚未完成。我需要修改语句,以便比较[Allocation]的连续值由[FeeEarner]和[CaseNo]分组/分区。

例如,在数据的第18行,[Allocation]为800,并与之前的600值进行比较。但之前的值属于不同的[CaseNo],即6而不是31.事实上[FeeEarner] ]'PJW'在[CaseNo]'31'之前没有[Allocation],因此[prevAllocation]应该是来自ISNULL关键字的'0'。

我尝试过更改

OVER (ORDER BY AllocID)

OVER (PARTITION BY CaseNo, FeeEarner ORDER BY AllocID) 

但这会导致大量数据被重复。

有人可以建议如何比较[分配]的连续值,但只能在匹配[FeeEarner]和[CaseNo]的数据行之间进行比较吗?

注意 - 我无法使用LAG,因为我的客户使用的是不支持并行数据仓库的SQL Server 2008 R2。

3 个答案:

答案 0 :(得分:3)

我相信你很亲密。试试这个(注意join子句中添加的部分以匹配分区 - 如果没有这个,你将匹配每个第3行,每行第2行跨越分区,这就是你所看到的):

;WITH cteMain AS
(
    SELECT AllocID, CaseNo, FeeEarner, Allocation, 
        ROW_NUMBER() OVER (PARTITION BY CaseNo, FeeEarner ORDER BY AllocID) AS sn
    FROM tblAllocations
)    
SELECT m.AllocID, m.CaseNo, m.FeeEarner, m.Allocation, 
       ISNULL(sLag.Allocation, 0) AS prevAllocation,
      (m.Allocation - ISNULL(sLag.Allocation, 0)) AS movement
FROM cteMain AS m

LEFT OUTER JOIN cteMain AS sLag
    ON sLag.CaseNo = m.CaseNo
    AND sLag.FeeEarner = m.FeeEarner
    AND sLag.sn = m.sn-1

答案 1 :(得分:0)

您还需要更改加入条件:

FROM cteMain m LEFT OUTER JOIN
     cteMain sLag
     ON sLag.sn = m.sn-1 and sLag.FeeEarner = m.FeeEarner and slag.CaseNo = m.CaseNo

此外,order by来电时,您应该只有一个row_number()

此外,如果您使用的是Oracle,SQL Server 2012,更新版本的DB2或Postgres,那么lead() / lag()函数将是更好的选择。

答案 2 :(得分:0)

使用OUTER APPLY和EXISTS

的另一个选项
SELECT t1.AllocID, t1.CaseNo, t1.FreeEarner, t1.Allocation, 
       ISNULL(o.Allocation, 0) AS PrevAllocation, 
       (t1.Allocation - ISNULL(o.Allocation, 0)) AS movement
FROM tblAllocations t1 
OUTER APPLY (
             SELECT t2.AllocID, t2.CaseNo, t2.FreeEarner, t2.Allocation
             FROM tblAllocations t2
             WHERE EXISTS (
                           SELECT 1
                           FROM tblAllocations t3
                           WHERE t1.AllocID > t3.AllocID
                           HAVING MAX(t3.AllocID) = t2.AllocID
                           ) AND t1.CaseNo = t2.CaseNo
             ) o