2013-06-16 43 views
7

Có một hàm trong PL/SQL để hiển thị loại chính xác của biến, như hàm DUMP trong SQL không?Cách xem loại biến trong PL/SQL?

Tôi đã thử những điều sau

DECLARE 
    l_variable INTEGER := 1; 
BEGIN 
    DBMS_OUTPUT.PUT_LINE (DUMP (l_variable)); 
END; 

Nhưng nó mang lại cho các lỗi sau:

PLS-00204: function or pseudo-column 'DUMP' may be used inside a SQL statement only

+1

Tại sao bạn muốn thực hiện việc này? DUMP() là một công cụ chẩn đoán, chủ yếu được sử dụng để điều tra * nội dung * của các cột trong bảng. Tại sao bạn cần thẩm vấn các kiểu dữ liệu của các biến PL/SQL? (Tôi có một vài giả thuyết, nhưng tôi nghĩ câu hỏi sẽ được cải thiện bằng nhiều chi tiết liên quan đến ca sử dụng.) – APC

+0

Ban đầu tôi chỉ muốn tìm ra chính xác kiểu biến vòng lặp tự động trong một số FOR LOOP. Sau đó, tôi bắt đầu tự hỏi làm thế nào tôi có thể lập trình có được loại thực tế của bất kỳ biến, giống như trong bất kỳ ngôn ngữ hiện đại như C#, java hoặc python, và tôi đã không tìm thấy bất kỳ cách nào. – csadam

Trả lời

5

Bạn có thể tạo chức năng này sử dụng PL/Scope. Nhưng nó sẽ không hoạt động với các khối ẩn danh và bạn sẽ cần phải tham chiếu biến này dưới dạng chuỗi.

create or replace function get_plsql_type_name 
(
    p_object_name varchar2, 
    p_name varchar2 
) return varchar2 is 
    v_type_name varchar2(4000); 
begin 
    select reference.name into v_type_name 
    from user_identifiers declaration 
    join user_identifiers reference 
     on declaration.usage_id = reference.usage_context_id 
     and declaration.object_name = reference.object_name 
    where 
     declaration.object_name = p_object_name 
     and declaration.usage = 'DECLARATION' 
     and reference.usage = 'REFERENCE' 
     and declaration.name = p_name; 

    return v_type_name; 
end; 
/

Ví dụ:

alter session set plscope_settings = 'IDENTIFIERS:ALL'; 

create or replace type my_weird_type is object 
(
    a number 
); 

create or replace procedure test_procedure is 
    var1 number; 
    var2 integer; 
    var3 my_weird_type; 
    subtype my_subtype is pls_integer range 42 .. 43; 
    var4 my_subtype; 
begin 
    dbms_output.put_line(get_plsql_type_name('TEST_PROCEDURE', 'VAR1')); 
    dbms_output.put_line(get_plsql_type_name('TEST_PROCEDURE', 'VAR2')); 
    dbms_output.put_line(get_plsql_type_name('TEST_PROCEDURE', 'VAR3')); 
    dbms_output.put_line(get_plsql_type_name('TEST_PROCEDURE', 'VAR4')); 
end; 
/

begin 
    test_procedure; 
end; 
/

NUMBER 
INTEGER 
MY_WEIRD_TYPE 
MY_SUBTYPE 
+0

Tôi chỉ nhận ra rằng điều này có thể chạy vào một số vấn đề tùy thuộc vào cách nó được sử dụng. Nếu biến không tồn tại, bạn sẽ nhận được một 'NO_DATA_FOUND' và nếu có hai biến có cùng tên trong đối tượng bạn sẽ nhận được' ORA-01422: tìm nạp chính xác trả về nhiều hơn số hàng được yêu cầu'. –

+0

Không sao, tôi có ý tưởng. Tôi chỉ sử dụng các phiên bản cũ hơn 11g nên tôi không biết về tính năng này. Có vẻ như tôi phải cập nhật kiến ​​thức của mình vì 12c cũng đã hết :) – csadam

1
declare 
    a number(10,3); 
    type_info varchar2(400); 
begin 
    a := 55.5; 
    select dump(a) into type_info from dual; 
    DBMS_OUTPUT.PUT_LINE(type_info); 
end; 
+2

Tôi đã nghĩ về giải pháp này, nhưng có chuyển đổi tiềm ẩn xảy ra trong trường hợp này. Ví dụ, nếu tôi vượt qua trong một PLS_INTEGER, nó sẽ trở thành một typ = 2 NUMBER. – csadam

+0

@csadam: Và đó là chính xác. PLS_INTEGER là một kiểu con của BINARY_INTEGER, là một kiểu con của INTEGER, là một bí danh cho NUMBER. Vì vậy, tôi đoán nó trả về giá trị chính xác. –

+0

@csadam: Nếu bạn nghĩ rằng bạn sẽ gọi một số proc/func dựa trên khám phá kiểu thì bạn đang đi sai hướng. Có một cách cho nó nhưng không được khuyến khích. –

2

như bạn nên để ý, DUMP là một chức năng quá tải. nó có 3 tình trạng quá tải.

Vì vậy, bạn có thể mô phỏng cùng một điều trong mã của mình.

function myDump (x Varchar2) return varchar2 is begin return('string') ; end ; 
function myDump (x number) return varchar2 is begin return('integer') ; end ; 
function myDump (x date) return varchar2 is begin return('date') ; end ; 

mã ở trên có thể không hoạt động đúng nhưng nên cung cấp cho bạn ý tưởng về cách giải quyết vấn đề.

Tôi hy vọng rằng điều này sẽ đáp ứng các yêu cầu của bạn.

Lưu ý; bạn có thể đặt các chức năng này trong một Gói và sử dụng chúng cho phù hợp.

+0

Giải pháp này sẽ không thể phân biệt giữa 'NUMBER' và' INTEGER'. Nếu bạn tạo một hàm cho mỗi loại trong một gói nó sẽ biên dịch, nhưng khi bạn gọi nó, bạn sẽ nhận được thông báo lỗi 'PLS-00307: quá nhiều khai báo' MYDUMP 'khớp với lệnh gọi này'. Phần thực sự phức tạp của câu hỏi này là phân biệt giữa các kiểu con, bởi vì PL/SQL dường như không biết sự khác biệt trong mọi ngữ cảnh. –

+0

Hi Ali, cách tiếp cận sáng tạo. Nó không hoàn hảo như @jonearles chỉ ra, nhưng vẫn tốt hơn so với những người khác trong các phiên bản DB dưới 11g. Tôi có thể chấp nhận điều này cho câu trả lời dưới 11g. Nhưng tôi đã không hạn chế các phiên bản DB trong câu hỏi, và giải pháp 11g là tốt hơn, vì vậy tôi phải cung cấp cho tiền thưởng để jonearles – csadam

+0

Những chức năng này sẽ chỉ làm việc cho oracle các loại bản địa. Và oracle Kiểu bản địa không tạo ra bất kỳ sự khác biệt nào giữa Số và Số nguyên. @jonearles đưa ra một lời giải thích tốt, lý do tôi đưa cho bạn một lựa chọn khác là bạn có thể có một yêu cầu đơn giản hơn. –