PL/SQL中如何查看变量的类型?

Posted

技术标签:

【中文标题】PL/SQL中如何查看变量的类型?【英文标题】:How to view the type of a variable in PL/SQL? 【发布时间】:2013-06-16 14:25:30 【问题描述】:

PL/SQL 中是否有显示变量确切类型的函数,如 SQL 中的 DUMP 函数?

我已经尝试了以下

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

但它给出了以下错误:

PLS-00204:函数或伪列“DUMP”可能在 SQL 中使用 仅声明

【问题讨论】:

为什么要这样做? DUMP() 是一个诊断工具,主要用于调查表列的内容。为什么需要询问 PL/SQL 变量的数据类型? (我有几个假设,但我认为通过有关用例的更多细节可以改进这个问题。) 最初我只是想在数字 FOR LOOP 中找出自动声明的循环变量的确切类型。然后我开始想知道如何以编程方式获取任何变量的实际类型,例如 C#、java 或 python 等任何现代语言,但我没有找到任何方法。 【参考方案1】:

您可以使用PL/Scope 创建此函数。但它不适用于匿名块,您需要将变量作为字符串引用。

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;
/

例子:

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

【讨论】:

我刚刚意识到这可能会遇到一些问题,具体取决于它的使用方式。如果变量不存在,您将获得NO_DATA_FOUND,如果对象中有两个同名变量,您将获得ORA-01422: exact fetch returns more than requested number of rows 没问题,我知道了。我只使用了 11g 以上的旧版本,所以我不知道这个功能。看来我必须更新我的知识,因为 12c 也出来了:)【参考方案2】:

您应该注意到,DUMP 是一个重载函数。它有 3 个重载。

因此您可以在代码中模拟相同的内容。

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 ;

上面的代码可能无法正常工作,但应该让你知道如何处理这个问题。

我希望这能满足您的要求。

注意;您可以将这些功能放在一个包中并相应地使用它们。

【讨论】:

此解决方案将无法区分 NUMBERINTEGER。如果您为包中的每种类型创建一个函数,它将编译,但是当您调用它时,您将收到错误消息PLS-00307: too many declarations of 'MYDUMP' match this call。这个问题真正棘手的部分是区分子类型,因为 PL/SQL 似乎并不知道每种情况下的区别。 嗨,阿里,创意方法。正如@jonearles 指出的那样,它并不完美,但在 11g 以下的 DB 版本中仍然比其他版本更好。对于 11g 以下的答案,我可以接受。但是问题里我没有限制DB版本,11g的方案更好,所以只好给jonearles赏金了 这些函数仅适用于 oracle 原生类型。并且 oracle Native 类型在 Number 和 Integer 之间没有任何区别。 @jonearles 给出了很好的解释,我给你另一个选择的原因是你可能有一个更简单的请求。【参考方案3】:
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;

【讨论】:

我已经考虑过这个解决方案,但是在这种情况下会发生隐式转换。例如,如果我传入一个 PLS_INTEGER,它就会变成 typ=2 NUMBER。 @csadam:这是正确的。 PLS_INTEGER 是 BINARY_INTEGER 的子类型,它是 INTEGER 的子类型,INTEGER 是 NUMBER 的别名。所以我猜它会返回正确的值。 @csadam:如果你认为你会根据类型发现调用一些 proc/func,那么你就走错了方向。有办法,但不推荐。 @the_slk 我的目的只是深入挖掘,看看幕后到底发生了什么。例如,在 .NET 中,我可以挖掘“虚拟”字节码,查看真正执行的内容,并查看优化器在我的源代码中发生了什么变化。没什么大不了的,只是好奇。

以上是关于PL/SQL中如何查看变量的类型?的主要内容,如果未能解决你的问题,请参考以下文章

如何在 PL/SQL 中查看存储过程的代码

oracle pl/sql如何定义变量

从 oracle PL/SQL 查看变量的值

PL/SQL 如何查看当前连接信息以及SQL PLUS如何指定IP地址

如何使用PL/SQL Developer查看和杀掉session

pl/sql如何现实像sqlserver中的树形结构目录界面,就是能查看表视图那样的界面。