2012-06-08 17 views
10

Oracle'da LISTAGG işlevi, OVER (PARTITION BY column..) yan tümcesiyle analitik olarak kullanmamı sağlar. Ancak, ROWS veya RANGE anahtar sözcükleriyle pencere kullanımını desteklemez.LISTAGG eşdeğeri pencere eşiği ile

Bir mağaza kaydında bir veri kümem var (soru için basitleştirilmiş). Kayıt tablosunun miktarının her zaman 1 - bir kalem, bir işlem satırı olduğunu unutmayın.

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 

Ben ürün miktarına göre gruplandırılmış bir özel sipariş sisteminde bir tabloya bu verileri "eşleşmesi" gerekir. Sistemin birden fazla satırda aynı öğe kimliğine sahip olabileceğini unutmayın (sipariş edilen öğeler, öğe aynı olsa bile farklı olabilir). Ben bu verileri eşleşebilir

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

sadece yolu sipariş kimliği, öğe kimliği ve dolar tutarı gereğidir.

Esasen aşağıdaki sonuca ulaşmam gerekiyor.

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 hatları herhangi bir şekilde sıralanır eğer özellikle Umurumda olan, umurumda değil dolar tutarları maç ve ben "yeniden kullanım" bilgi işlem kaydından bir çizgi yapmak Özel siparişte toplam. Tabloya ayrılan tran çizgilerine ihtiyacım yok - bu raporlama amaçlıdır ve taneciklik asla kayıt işlem hattı seviyesine geri dönmez.

İlk düşüncem, sipariş sistemindeki dolar tutarı ve miktarı ile eşleşen ilk satır kümesini tanımlamak için "en iyi eşleşme" yapmak için analitik işlevlerle bunu yapabilmem gerekti. :

( ) Ama sonra benim sorguya LISTAGG eklemeyi deneyin:

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 

Tabii hep yerine birikimli AGG tam agg döndürdüğünü keşfetmek:

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 

Yani bu kullanışlı değildir.

Mümkünse bunu SQL'de yapmayı tercih ederim. Bunu imleçler & prosedürel mantık ile yapabileceğimin farkındayım.

LISTAGG analitik işlevi veya bunu destekleyen başka bir analitik işlevle pencereleme yapmanın bir yolu var mı?

11gR2'deyim. Bunu başarmak için aklınıza gelebilecek

+2

+1. – DCookie

cevap

7

tek yolu bir ilişkili alt sorgu: Ben bu için soran kesin çıkış vermez gerçekleştirmek

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; 

ama umarım üstesinden gelmek için yeterlidir birikimli LISTAGG sorunu ve sizi yolda.

Çözümü göstermek için bir SQL Fiddle kurdum.

+0

Teşekkürler. Sağladığım ilk örnek için çalışıyor, ancak ek işlemler/öğeler eklediğimde, bir "ORA-01427: tek satırlı alt sorgunun birden çok satır döndürmesi" hatası alıyorum. Sanırım aradığımı yapmak için sorgunuzu değiştirebilirim. İşte bu hatayı atar bir örnek: http://sqlfiddle.com/#!4/53b4d/1 –

+1

Ayrıca - SQLFiddle? Fantastik! Yer işaretlerini kesin olarak kabul etmek. –

+0

Tek yapmam gereken alt sorgudaki birleştirmeye 've t1.itemid = t2.itemid ve t1.orderid = t2.orderid ve t1.tranid = t2.tranid'. Cevabı güncelleyebilir ve kabul edeceğim. –

2

Örneğinizde, mağaza kayıt tablonuz 5 satır içerir ve özel sipariş sistem tablonuzda 2 satır bulunur. Beklenen sonuç kümeniz, özel sipariş sistem tablonuzun iki satırını ve mağaza kayıt tablonuzun tüm "tranlines" larını "Tran Line" sütununda belirtmelidir.

Bu 5 satırı 2 satıra ayırmanız gerektiği anlamına gelir. LISTAGG analitik fonksiyonuna değil, LISTAGG agrega fonksiyonuna ihtiyacınız yoktur.

Yüklemeniz, özel kayıt sistemi tablosundaki mağaza kayıt çizelgesi satırlarını sağdaki satıra birleştirmektir. Dolar ve miktarların koşan toplamını hesaplayarak yolunuzda iyiydiniz. Eksik olan tek adım, her bir mağaza siparişi satırını her özel sipariş sistemi satırına atayabileceğiniz dolar ve miktar aralıkları tanımlamaktır.

İşte bir örnek. İlk tablolar tanımlayın:

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. 

Ve sorguyu:

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. 

Saygılarımızla,
Rob. Çok iyi yazılmış ilginç bir soru için

+0

Teşekkürler! Bunu yapmak için ilginç bir yol. Örnek veriler için iyi çalışıyor. Sipariş tablosunda aynı $ miktarlarla iki satır olduğunda bir sorun ortaya çıkar. Bir göz atın: http://sqlfiddle.com/#!4/06e72/1. Sipariş satırı 2, beş tane olmasına rağmen sadece eşleşen bir tran çizgisini gösterir. Çalışmayı başarabilir miyim diye sorgayla etrafta oynayacağım. –

+0

Üzgünüm - Eklerimde yazım hatası vardı, öğe kimlikleri farklıydı. Yine de bir sorun, ancak "kalan" 2.99 maddesini sipariş tablosundaki 14.95 öğeyle eşleştiriyorsa. –

+0

Bu akşam ona bakacağım. –

İlgili konular