此链接显示如何在Oracle中获取过程/函数变量的类型:View Type of a variable。
它通过“get_plsql_type_name”函数实现:
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;
/
上述方法的问题在于它是静态的,我需要验证变量的类型,该变量可以是过程/函数范围中声明的变量的子类型。
使用上述方法,我得到以下内容。
Create the type and its subtype:
create or replace type my_weird_type is object
(
a number
) NOT FINAL;
CREATE OR REPLACE TYPE my_weird_subtype UNDER my_weird_type(
b number
);
/
创建一个表并填充它:
create table test_my_weird_type(
x my_weird_type,
y my_weird_subtype
);
INSERT INTO test_my_weird_type (x,y) VALUES (my_weird_type(100),my_weird_subtype(100,200));
COMMIT;
函数创建(它有两个my_weird_type参数,有时候我需要使用它的子类型):
create or replace function test_procedure (
inn_type my_weird_type,
out_subtype my_weird_type
) RETURN number is
var1 number;
var2 integer;
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', 'INN_TYPE'));
dbms_output.put_line(get_plsql_type_name('TEST_PROCEDURE', 'OUT_SUBTYPE'));
return 1;
end;
/
下面的查询:
select test_procedure(x,y) from test_my_weird_type;
提供以下输出:
NUMBER
INTEGER
MY_WEIRD_TYPE
MY_WEIRD_TYPE
但是,正确的输出是:
NUMBER
INTEGER
MY_WEIRD_TYPE
MY_WEIRD_SUBTYPE
该功能需要识别所使用的子类型,因此 函数“get_plsql_type_name”需要改进。有办法吗?
答案 0 :(得分:2)
您无法根据函数规范测试类型,但可以使用IS OF( type )
运算符或SYS_TYPEID
function来测试传入对象的类型:
Oracle 11g R2架构设置:
CREATE type my_weird_type IS OBJECT
(
a NUMBER
) NOT FINAL
/
CREATE TYPE my_weird_subtype UNDER my_weird_type
(
b NUMBER
)
/
CREATE FUNCTION getType(
i_type my_weird_type
) RETURN VARCHAR2
IS
BEGIN
IF i_type IS OF( my_weird_subtype ) THEN
RETURN 'subtype';
ELSIF i_type IS OF( my_weird_type ) THEN
RETURN 'type';
ELSE
RETURN 'other';
END IF;
END;
/
CREATE FUNCTION getType2(
i_type my_weird_type
) RETURN VARCHAR2
IS
o_type USER_TYPES.TYPE_NAME%TYPE;
BEGIN
SELECT type_name
INTO o_type
FROM user_types
WHERE typeid = SYS_TYPEID( i_type );
RETURN o_type;
EXCEPTION
WHEN NO_DATA_FOUND THEN
RETURN NULL;
END;
/
create table test_my_weird_type(
value my_weird_type
)
/
INSERT INTO test_my_weird_type (value)
SELECT my_weird_type(1) FROM DUAL UNION ALL
SELECT my_weird_subtype(2,3) FROM DUAL UNION ALL
SELECT NULL FROM DUAL
/
查询1 :
SELECT t.value.a AS a,
TREAT( t.value AS my_weird_subtype ).b AS b,
getType( value ),
getType2( value )
FROM test_my_weird_type t
<强> Results 强>:
| A | B | GETTYPE(VALUE) | GETTYPE2(VALUE) |
|--------|--------|----------------|------------------|
| 1 | (null) | type | MY_WEIRD_TYPE |
| 2 | 3 | subtype | MY_WEIRD_SUBTYPE |
| (null) | (null) | other | (null) |
答案 1 :(得分:1)
因此,该函数需要识别所使用的子类型 函数“get_plsql_type_name”需要改进。有没有 这样做的方法?
没有。没有办法。 Oracle
显示有关当前用户拥有的存储对象中的标识符的信息,如(包/过程/函数等)。
SQL
不会为在TYPE
范围内创建的独立对象提供任何数据字典,以识别SUBTYPE
和TYPE
。您最多可以将其标识为TYPE
。
例如,在您的情况下,下面的一个只会返回SUBTYPE
,甚至认为它是SELECT *
FROM all_objects
WHERE object_name = 'MY_WEIRD_SUBTYPE'
。
Type
编辑:
我能想到的另一种方法是检查您传递的SUPERTYPE
是否有type
。如果是,则意味着subtype
是SELECT 1
FROM user_types
WHERE type_name = 'MY_WEIRD_SUBTYPE'
and supertype_name is not null;
。
您可以使用以下查询:
SUBTYPE
您可以在函数中实现此功能,以检查其是compile 'com.google.android.gms:play-services:7.8.0'
还是
答案 2 :(得分:1)
ANYDATA和ANYTYPE允许对Oracle对象进行完整的动态控制。这种方法与静态代码分析方法无关。
例如,此函数返回任何对象输入的实际类型名称:
create or replace function get_dynamic_type_name(
p_anydata anydata
) return varchar2 is
v_typecode pls_integer;
v_anytype anytype;
v_prec pls_integer;
v_scale pls_integer;
v_len pls_integer;
v_csid pls_integer;
v_csfrm pls_integer;
v_schema_name varchar2(128);
v_type_name varchar2(128);
v_version varchar2(32767);
v_numelems pls_integer;
v_result pls_integer;
begin
v_typecode := p_anydata.getType(v_anytype);
v_result := v_anytype.GetInfo
(
prec => v_prec,
scale => v_scale,
len => v_len,
csid => v_csid,
csfrm => v_csfrm,
schema_name => v_schema_name,
type_name => v_type_name,
version => v_version,
numelems => v_numelems
);
return v_type_name;
end get_dynamic_type_name;
/
在调用函数之前,必须使用AnyData.ConvertObject
转换对象:
select
get_type_name(AnyData.ConvertObject(x)) x_type,
get_type_name(AnyData.ConvertObject(y)) y_type
from test_my_weird_type;
X_TYPE Y_TYPE
------ ------
MY_WEIRD_TYPE MY_WEIRD_SUBTYPE
该函数可能不是简单获取类型名称的最方便的方法。但它演示了如何使用ANY类型来实现PL / SQL反射和操作对象,而无需提前了解它们。例如,我的回答是基于我的另一个答案here,它演示了如何找到对象的第一个属性。
任何类型都很有趣,但应谨慎使用。使用动态SQL生成处理数据的静态代码通常更快更容易,而不是在动态代码中进行所有处理。我尽可能避免使用对象关系数据库功能。让你的架构变得聪明,但让你的列变得愚蠢。