2012-06-25 14 views
8

Đoạn mã dưới đây tôi không thể khai báo kiểu nạp vào biến như% ROWTYPE của bảng bên dưới vì SYS_REFCURSOR nằm trên một phép chọn nối hai bảng và cũng chọn một vài hàm được gọi trên các thuộc tính của hai bảng bên dưới; tức là tôi không thể tuyên bố như L_RECORD T% ROWTYPEcách khai báo% ROWTYPE của biến là một SYS_REFCURSOR được đánh máy yếu?

--- 
DECLARE 
    P_RS SYS_REFCURSOR; 
    L_RECORD P_RS%ROWTYPE; 
BEGIN 
    CAPITALEXTRACT(
    P_RS => P_RS 
); 
    OPEN P_RS; 
    LOOP 
     BEGIN 
     FETCH P_RS INTO L_RECORD; 
     EXIT WHEN P_RS%NOTFOUND; 
     ... 
     EXCEPTION 
     WHEN OTHERS THEN 
     ... 
     END; 
    END LOOP; 
    CLOSE P_RS; 
END; 
-------- 
CREATE or REPLACE PROCEDURE CAPITALEXTRACT 
(
    p_rs OUT SYS_REFCURSOR 
) AS 
BEGIN 
    OPEN p_rs for 
    select t.*,tminusone.*, f(t.cash), g(t.cash) FROM T t, TMINUSONE tminusone 
    where t.ticket=tminusone.ticket; 
END CAPITALEXTRACT; 

Dĩ nhiên tôi không muốn xác định một bảng R tĩnh với các cột như trả lại trong SYS_REFCURSOR và sau đó tuyên bố như L_RECORD R ROWTYPE%.

Và do đó, câu hỏi: cách khai báo% ROWTYPE của biến là một SYS_REFCURSOR được đánh máy yếu?

Trả lời

14

Câu trả lời ngắn gọn là bạn không thể. Bạn cần phải xác định một biến cho mỗi cột được trả về.

DECLARE 
    P_RS SYS_REFCURSOR; 
    L_T_COL1 T.COL1%TYPE; 
    L_T_COL1 T.COL2%TYPE; 
    ... 

Và sau đó lấy vào danh sách các cột:

FETCH P_RS INTO L_T_COL1, L_T_COL2, ... ; 

Đây là đau đớn nhưng quản lý được miễn là bạn biết những gì bạn đang mong đợi ở con trỏ ref. Sử dụng T.* trong thủ tục của bạn làm cho điều này mỏng manh mặc dù, việc thêm một cột vào bảng sẽ phá vỡ mã mà nghĩ rằng nó biết những gì cột có và thứ tự họ đang ở. (Bạn cũng có thể phá vỡ nó giữa các môi trường nếu các bảng aren ' t được xây dựng nhất quán - Tôi đã nhìn thấy những nơi mà thứ tự cột khác nhau trong các môi trường khác nhau). Có thể bạn sẽ muốn đảm bảo rằng bạn chỉ chọn các cột mà bạn thực sự quan tâm, để tránh phải xác định các biến cho những thứ bạn sẽ không bao giờ đọc.

Từ 11g bạn có thể sử dụng gói DBMS_SQL để chuyển đổi sys_refcursor thành con trỏ DBMS_SQL và bạn có thể thẩm vấn để xác định cột. Cũng như một ví dụ về những gì bạn có thể làm, điều này sẽ in ra giá trị của mỗi cột trong mỗi hàng, với tên cột:

DECLARE 
    P_RS SYS_REFCURSOR; 
    L_COLS NUMBER; 
    L_DESC DBMS_SQL.DESC_TAB; 
    L_CURS INTEGER; 
    L_VARCHAR VARCHAR2(4000); 
BEGIN 
    CAPITALEXTRACT(P_RS => P_RS); 
    L_CURS := DBMS_SQL.TO_CURSOR_NUMBER(P_RS); 
    DBMS_SQL.DESCRIBE_COLUMNS(C => L_CURS, COL_CNT => L_COLS, 
     DESC_T => L_DESC); 

    FOR i IN 1..L_COLS LOOP 
     DBMS_SQL.DEFINE_COLUMN(L_CURS, i, L_VARCHAR, 4000); 
    END LOOP; 

    WHILE DBMS_SQL.FETCH_ROWS(L_CURS) > 0 LOOP 
     FOR i IN 1..L_COLS LOOP 
      DBMS_SQL.COLUMN_VALUE(L_CURS, i, L_VARCHAR); 
      DBMS_OUTPUT.PUT_LINE('Row ' || DBMS_SQL.LAST_ROW_COUNT 
       || ': ' || l_desc(i).col_name 
       || ' = ' || L_VARCHAR); 
     END LOOP; 
    END LOOP; 

    DBMS_SQL.CLOSE_CURSOR(L_CURS); 
END; 
/

Đó không phải là của nhiều ứng dụng thực tế, và cho ngắn gọn tôi đối xử với mỗi giá trị như một chuỗi kể từ khi tôi chỉ muốn in nó anyway. Xem các tài liệu và tìm kiếm các ví dụ cho các ứng dụng thực tế hơn.

Nếu bạn chỉ muốn một vài cột từ con trỏ ref, bạn có thể giả sử, vòng quanh l_desc và ghi lại vị trí mà column_name là bất kỳ thứ gì bạn quan tâm, dưới dạng biến số; sau đó bạn có thể tham khảo cột theo biến đó sau đó, nơi bạn thường sử dụng tên trong vòng lặp con trỏ. Phụ thuộc vào những gì bạn đang làm với dữ liệu.

Nhưng trừ khi bạn đang mong đợi để không biết thứ tự cột bạn đang nhận lại, điều này dường như không có khả năng kiểm soát quy trình - và giả sử bạn loại bỏ .* s - có thể bạn đang tốt hơn giảm giảm các cột được trả lại đến mức tối thiểu bạn cần và chỉ tuyên bố tất cả các cột riêng lẻ.

+0

Người đàn ông tuyệt vời, tôi đã tìm kiếm một năm để làm điều này và điều này giải thích nó là tốt nhất. Lưu ý: Tôi không cần CAPITALEXTRACT (P_RS => P_RS); hàng. (trong thực tế nó sai, không chắc chắn những gì nó đã làm vì vậy tôi nhận xét ra và pl/sql của tôi sau đó chạy gloriously) – armyofda12mnkeys

+0

@ armyofda12mnkeys - vui vì nó đã giúp. CAPITALEXTRACT là một hàm dành riêng cho câu hỏi này, không phải là một cái gì đó thực chất đối với giải pháp, vì vậy đừng lo lắng về điều đó. –

Các vấn đề liên quan