Oracle
 sql >> Teknologi Basis Data >  >> RDS >> Oracle

Pivot Oracle dengan subquery

Apakah Anda mempertimbangkan untuk menggunakan fungsi PIPELINED untuk mencapai tujuan Anda?

Saya telah menulis contoh fungsi seperti itu. Contoh berdasarkan tabel, data sampel dan PIVOT kueri dari artikel Tom Kyte yang dapat Anda temukan di situsnya:

Artikel Tom Kyte tentang PIVOT/UNPIVOT

Artikel Tom Kyte tentang fungsi PIPELINED

Contoh berfungsi sebagai berikut.

Kami membuat dua jenis:

  • t_pivot_test_obj - ketik yang menampung kolom yang ingin kita ambil dari XML
  • t_pivot_test_obj_tab - jenis tabel bersarang dari objek di atas.

Kemudian kita membuat fungsi PIPELINED yang berisi query dengan PIVOT , yang menghasilkan XML (sehingga Anda tidak perlu melakukan hard-code pada nilai yang ingin Anda putar). Fungsi ini mengekstrak data dari XML yang dihasilkan dan meneruskan (PIPE) baris ke kueri panggilan saat dibuat (dengan cepat - tidak dibuat sekaligus yang penting untuk kinerja).

Terakhir, Anda menulis kueri yang memilih catatan dari fungsi itu (di bagian akhir adalah contoh kueri semacam itu).

CREATE TABLE pivot_test (
  id            NUMBER,
  customer_id   NUMBER,
  product_code  VARCHAR2(5),
  quantity      NUMBER
);

INSERT INTO pivot_test VALUES (1, 1, 'A', 10);
INSERT INTO pivot_test VALUES (2, 1, 'B', 20);
INSERT INTO pivot_test VALUES (3, 1, 'C', 30);
INSERT INTO pivot_test VALUES (4, 2, 'A', 40);
INSERT INTO pivot_test VALUES (5, 2, 'C', 50);
INSERT INTO pivot_test VALUES (6, 3, 'A', 60);
INSERT INTO pivot_test VALUES (7, 3, 'B', 70);
INSERT INTO pivot_test VALUES (8, 3, 'C', 80);
INSERT INTO pivot_test VALUES (9, 3, 'D', 90);
INSERT INTO pivot_test VALUES (10, 4, 'A', 100);
COMMIT;

CREATE TYPE t_pivot_test_obj AS OBJECT (
  customer_id   NUMBER,
  product_code  VARCHAR2(5),
  sum_quantity  NUMBER
);
/

CREATE TYPE t_pivot_test_obj_tab IS TABLE OF t_pivot_test_obj;
/

CREATE OR REPLACE FUNCTION extract_from_xml RETURN t_pivot_test_obj_tab PIPELINED
AS
  v_xml XMLTYPE;
  v_item_xml XMLTYPE;
  v_index NUMBER;
  v_sum_quantity NUMBER;

  CURSOR c_customer_items IS
    SELECT customer_id, product_code_xml
      FROM (SELECT customer_id, product_code, quantity
              FROM pivot_test)
      PIVOT XML (SUM(quantity) AS sum_quantity FOR (product_code) IN (SELECT DISTINCT product_code 
                                                                      FROM pivot_test));
BEGIN
  -- loop through all records returned by query with PIVOT
  FOR v_rec IN c_customer_items
  LOOP
    v_xml := v_rec.product_code_xml;
    v_index := 1;

    -- loop through all ITEM elements for each customer
    LOOP
      v_item_xml := v_xml.EXTRACT('/PivotSet/item[' || v_index || ']');

      EXIT WHEN v_item_xml IS NULL;

      v_index := v_index + 1;

      IF v_item_xml.EXTRACT('/item/column[@name="SUM_QUANTITY"]/text()') IS NOT NULL THEN
        v_sum_quantity := v_item_xml.EXTRACT('/item/column[@name="SUM_QUANTITY"]/text()').getNumberVal();
      ELSE
        v_sum_quantity := 0;
      END IF;

      -- finally, for each customer and item - PIPE the row to the calling query
      PIPE ROW(t_pivot_test_obj(v_rec.customer_id,
                                v_item_xml.EXTRACT('/item/column[@name="PRODUCT_CODE"]/text()').getStringVal(),
                                v_sum_quantity));
    END LOOP;
  END LOOP;
END;
/

SELECT customer_id, product_code, sum_quantity
  FROM TABLE(extract_from_xml())
;

Keluaran:

CUSTOMER_ID            PRODUCT_CODE SUM_QUANTITY           
---------------------- ------------ ---------------------- 
1                      A            10                     
1                      B            20                     
1                      C            30                     
1                      D            0                      
2                      A            40                     
2                      B            0                      
2                      C            50                     
2                      D            0                      
3                      A            60                     
3                      B            70                     
3                      C            80                     
3                      D            90                     
4                      A            100                    
4                      B            0                      
4                      C            0                      
4                      D            0                      

16 rows selected


  1. Database
  2.   
  3. Mysql
  4.   
  5. Oracle
  6.   
  7. Sqlserver
  8.   
  9. PostgreSQL
  10.   
  11. Access
  12.   
  13. SQLite
  14.   
  15. MariaDB
  1. Cara terbaik membagi string csv di Oracle 9i

  2. Apakah ada cara untuk memaksa OracleCommand.BindByName menjadi true secara default untuk ODP.NET?

  3. Pilih Kumpulkan Massal ke Contoh Oracle

  4. Bagaimana cara menjatuhkan tabel di oracle

  5. Apa topeng pemformatan tanggal Oracle untuk zona waktu?