10

オラクルでは、関数を使用すると、句LISTAGGで分析的に使用できます。OVER (PARTITION BY column..)ただし、ROWSまたはRANGEキーワードによるウィンドウ処理の使用はサポートされていません。

店舗レジスターからのデータセットがあります(質問のために簡略化されています)。登録テーブルの数量は常に 1 であることに注意してください。つまり、1 つのアイテム、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

このデータを、アイテムが数量別にグループ化される特別注文システムのテーブルに「一致」させる必要があります。システムでは、複数のラインで同じアイテム ID を持つことができることに注意してください (アイテムが同じであっても、注文されたコンポーネントは異なる場合があります)。

ItemId OrderID Order Line Dollars Quantity
------ ------- ---------- ------- --------
23845  23      1          8.97    3
23845  23      2          5.98    2

このデータを照合できる唯一の方法は、注文 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

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

ここまでは順調ですね。しかし、次にクエリに 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

累積集計ではなく、常に完全な集計を返すことがわかりました。

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

したがって、これは役に立ちません。

可能であれば、SQLでこれを行うことをお勧めします。カーソルと手続き型ロジックを使用してこれを実行できることを認識しています。

LISTAGG 分析関数、またはこれをサポートする別の分析関数でウィンドウ処理を行う方法はありますか?

私は11gR2を使用しています。

4

2 に答える 2

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;

これはあなたが求めていた正確な出力を提供しないことを私は理解していますが、うまくいけば、累積的なLISTAGGの問題を克服し、あなたを道に導くのに十分です。

解決策を示すためにSQLフィドルを設定しました。

于 2012-06-08T19:36:19.523 に答える
2

この例では、店舗レジスタ テーブルに 5 行が含まれ、特注システム テーブルに 2 行が含まれています。予想される結果セットには、特注システム テーブルからの 2 つの行が含まれており、店舗レジスター テーブルのすべての "tranlines" が "Tran Line" 列に記載されている必要があります。

これは、これらの 5 行を 2 行に集約する必要があることを意味します。つまり、LISTAGG 分析関数は必要ありませんが、LISTAGG 集計関数は必要です。

あなたの課題は、店舗レジスタ テーブルの行を特注システム テーブルの右側の行に結合することです。ドルと数量の現在の合計を計算することで、順調に進んでいます。欠けている唯一の手順は、各店舗登録簿の行を各特別注文システムの行に割り当てることができる金額と数量の範囲を定義することです。

ここに例があります。最初にテーブルを定義します。

SQL> create table store_register_table (tranid,tranline,itemid,orderid,dollars,quantity)
  2  as
  3  select 1, 101, 23845, 23, 2.99, 1 from dual union all
  4  select 1, 102, 23845, 23, 2.99, 1 from dual union all
  5  select 1, 103, 23845, 23, 2.99, 1 from dual union all
  6  select 1, 104, 23845, 23, 2.99, 1 from dual union all
  7  select 1, 105, 23845, 23, 2.99, 1 from dual
  8  /

Table created.

SQL> create table special_order_system_table (itemid,orderid,order_line,dollars,quantity)
  2  as
  3  select 23845, 23, 1, 8.97, 3 from dual union all
  4  select 23845, 23, 2, 5.98, 2 from dual
  5  /

Table created.

そしてクエリ:

SQL> with t as
  2  ( select tranid
  3         , tranline
  4         , itemid
  5         , orderid
  6         , sum(dollars) over (partition by itemid,orderid order by tranline) running_sum_dollars
  7         , sum(quantity) over (partition by itemid,orderid order by tranline) running_sum_quantity
  8      from store_register_table srt
  9  )
 10  , t2 as
 11  ( select itemid
 12         , orderid
 13         , order_line
 14         , dollars
 15         , quantity
 16         , sum(dollars) over (partition by itemid,orderid order by order_line) running_sum_dollars
 17         , sum(quantity) over (partition by itemid,orderid order by order_line) running_sum_quantity
 18      from special_order_system_table
 19  )
 20  , t3 as
 21  ( select itemid
 22         , orderid
 23         , order_line
 24         , dollars
 25         , quantity
 26         , 1 + lag(running_sum_dollars,1,0) over (partition by itemid,orderid order by order_line) begin_sum_dollars
 27         , running_sum_dollars end_sum_dollars
 28         , 1 + lag(running_sum_quantity,1,0) over (partition by itemid,orderid order by order_line) begin_sum_quantity
 29         , running_sum_quantity end_sum_quantity
 30      from t2
 31  )
 32  select t3.itemid "ItemID"
 33       , t3.orderid "OrderID"
 34       , t3.order_line "Order Line"
 35       , t3.dollars "Dollars"
 36       , t3.quantity "Quantity"
 37       , t.tranid "Tran ID"
 38       , listagg(t.tranline,';') within group (order by t3.itemid,t3.orderid) "Tran Lines"
 39    from t3
 40         inner join t
 41           on (   t.itemid = t3.itemid
 42              and t.orderid = t3.orderid
 43              and t.running_sum_dollars between t3.begin_sum_dollars and t3.end_sum_dollars
 44              and t.running_sum_quantity between t3.begin_sum_quantity and t3.end_sum_quantity
 45              )
 46   group by t3.itemid
 47       , t3.orderid
 48       , t3.order_line
 49       , t3.dollars
 50       , t3.quantity
 51       , t.tranid
 52  /

    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

2 rows selected.

よろしく、
ロブ。

于 2012-06-10T09:59:04.730 に答える