Oracle
 sql >> Cơ Sở Dữ Liệu >  >> RDS >> Oracle

Oracle pivot với truy vấn con

Bạn có cân nhắc sử dụng hàm PIPELINED để đạt được mục tiêu của mình không?

Tôi đã viết một ví dụ về một chức năng như vậy. Ví dụ dựa trên bảng, dữ liệu mẫu và PIVOT truy vấn từ các bài báo của Tom Kyte mà bạn có thể tìm thấy trên trang web của anh ấy:

Bài viết của Tom Kyte về PIVOT / UNPIVOT

Bài viết của Tom Kyte về các hàm PIPELINED

Ví dụ hoạt động như sau.

Chúng tôi tạo ra hai loại:

  • t_pivot_test_obj - loại chứa các cột mà chúng tôi muốn truy xuất từ ​​XML
  • t_pivot_test_obj_tab - loại bảng lồng nhau của các đối tượng ở trên.

Sau đó, chúng tôi tạo một hàm PIPELINED chứa truy vấn với PIVOT , tạo ra XML (vì vậy bạn không cần phải viết mã cứng các giá trị mà bạn muốn xoay qua). Hàm này trích xuất dữ liệu từ XML đã tạo và chuyển các hàng (PIPE) tới truy vấn đang gọi khi chúng được tạo (nhanh chóng - chúng không được tạo cùng một lúc, điều này rất quan trọng đối với hiệu suất).

Cuối cùng, bạn viết một truy vấn chọn các bản ghi từ hàm đó (ở cuối là một ví dụ về truy vấn như vậy).

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())
;

Đầu ra:

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. Oracle có lưu trữ các số 0 ở cuối cho kiểu dữ liệu Số không?

  2. Cách giải quyết ORA-29285:lỗi ghi tệp

  3. Giải thích về toán tử Oracle MINUS

  4. ORACLE Kết nối theo mệnh đề tương đương trong SQL Server

  5. Xóa các hàng khỏi bảng mẹ và bảng con