LISTAGG等效于窗口子句

N W*_*est 10 sql oracle oracle11g

在oracle中,该LISTAGG函数允许我通过OVER (PARTITION BY column..)子句分析地使用它.但是,它不支持使用带ROWSRANGE关键字的窗口.

我有一个来自商店注册的数据集(针对该问题进行了简化).请注意,寄存器表的数量始终为1 - 一项,一个事务行.

TranID TranLine ItemId OrderID Dollars Quantity
------ -------- ------ ------- ------- --------
1      101      23845  23      2.99    1
1      102      23845  23      2.99    1
1      103      23845  23      2.99    1
1      104      23845  23      2.99    1
1      105      23845  23      2.99    1
Run Code Online (Sandbox Code Playgroud)

我必须将此数据"匹配"到特殊订单系统中的表格,其中项目按数量分组.请注意,系统可以在多行上具有相同的项目ID(即使项目相同,订购的组件也可能不同).

ItemId OrderID Order Line Dollars Quantity
------ ------- ---------- ------- --------
23845  23      1          8.97    3
23845  23      2          5.98    2
Run Code Online (Sandbox Code Playgroud)

我可以匹配此数据的唯一方法是订单ID,商品ID和金额.

基本上我需要得到以下结果.

ItemId OrderID Order Line Dollars Quantity Tran ID  Tran Lines
------ ------- ---------- ------- -------- -------  ----------
23845  23      1          8.97    3        1        101;102;103
23845  23      2          5.98    2        1        104;105
Run Code Online (Sandbox Code Playgroud)

我并不特别在意是否以任何方式订购了转发行,我所关心的是美元金额是否匹配,并且在计算特殊订单的总额时我没有"重新使用"来自寄存器的一行.我不需要将tran行分解为表 - 这是出于报告目的而且粒度永远不会回到寄存器事务行级别.

我最初的想法是,我可以使用分析函数执行此操作以执行"最佳匹配",以识别与订购系统中的美元金额和数量匹配的第一组行,为我提供如下结果集:

TranID TranLine ItemId OrderID Dollars Quantity CumDollar  CumQty
------ -------- ------ ------- ------- -------- --------   ------
1      101      23845  23      2.99    1        2.99       1
1      102      23845  23      2.99    1        5.98       2
1      103      23845  23      2.99    1        8.97       3
1      104      23845  23      2.99    1        11.96      4
1      105      23845  23      2.99    1        14.95      5
Run Code Online (Sandbox Code Playgroud)

到现在为止还挺好.但我尝试将LISTAGG添加到我的查询中:

SELECT tranid, tranline, itemid, orderid, dollars, quantity, 
       SUM(dollars) OVER (partition by tranid, itemid, orderid order by tranline) cumdollar,
       SUM(quantity) OVER (partition by tranid, itemid, orderid order by tranline) cumqty
       LISTAGG (tranline) within group (order by tranid, itemid, orderid, tranline) OVER (partition by tranid, itemid, orderid)
FROM table
Run Code Online (Sandbox Code Playgroud)

我发现它总是返回一个完整的agg而不是累积的agg:

TranID TranLine ItemId OrderID Dollars Quantity CumDollar  CumQty ListAgg
------ -------- ------ ------- ------- -------- --------   ------ -------
1      101      23845  23      2.99    1        2.99       1      101;102;103;104;105
1      102      23845  23      2.99    1        5.98       2      101;102;103;104;105
1      103      23845  23      2.99    1        8.97       3      101;102;103;104;105
1      104      23845  23      2.99    1        11.96      4      101;102;103;104;105
1      105      23845  23      2.99    1        14.95      5      101;102;103;104;105
Run Code Online (Sandbox Code Playgroud)

所以这没用.

如果可能的话,我更愿意在SQL中执行此操作.我知道我可以用游标和程序逻辑来做到这一点.

是否有任何方法可以使用LISTAGG分析函数进行窗口化,或者可能是另一种支持此功能的分析函数?

我在11gR2.

Gar*_*thD 7

我能想到实现这一目标的唯一方法是使用相关的子查询:

WITH CTE AS
(   SELECT  TranID, 
            TranLine, 
            ItemID, 
            OrderID, 
            Dollars, 
            Quantity, 
            SUM(dollars) OVER (PARTITION BY TranID, ItemID, OrderID ORDER BY TranLine) AS CumDollar, 
            SUM(Quantity) OVER (PARTITION BY TranID, ItemID, OrderID ORDER BY TranLine) AS CumQuantity
    FROM    T
)
SELECT  TranID, 
        TranLine, 
        ItemID, 
        OrderID, 
        Dollars, 
        Quantity, 
        CumDollar, 
        CumQuantity, 
        (   SELECT  LISTAGG(Tranline, ';') WITHIN GROUP(ORDER BY CumQuantity)
            FROM    CTE T2
            WHERE   T1.CumQuantity >= T2.CumQuantity
            AND     T1.ItemID = T2.ItemID
            AND     T1.OrderID = T2.OrderID
            AND     T1.TranID = T2.TranID
            GROUP BY tranid, itemid, orderid
        ) AS ListAgg
FROM    CTE T1;
Run Code Online (Sandbox Code Playgroud)

我意识到这并没有给出你要求的确切输出,但希望它足以克服累积LISTAGG的问题并让你继续前进.

我已经建立了一个SQL小提琴来演示解决方案.

  • 还有-SQLFiddle?极好的!肯定会进入书签。 (2认同)