寻找不同 Oracle 类型的 NULL 值
Looking NULL values for different Oracle Type
我正在收集两列 (col & val)。进入第二个select col是其他列的参数,val是该列的值。
declare
TYPE t_my_list is record(id varchar2(1000), col VARCHAR2(4000),val VARCHAR2(4000));
TYPE list_3STR is table of t_my_list;
v_stmt VARCHAR2(32000) := 'SELECT id, col, val FROM userA.tableA';
v_lstmt VARCHAR2(32000);
v_ret list_3STR := list_3STR();
cDel number;
begin
EXECUTE IMMEDIATE v_stmt BULK COLLECT INTO v_ret;
for i in v_ret.first..v_ret.last loop
v_lstmt := 'SELECT count(*) FROM userB.tableB
WHERE NVL('||v_ret (i).col||', ''<null>'') in ('''||v_ret (i).val||''', ''<null>'') and idB = '''||v_ret (i).id||'''';
EXECUTE IMMEDIATE v_lstmt INTO cDel;
If cDel > 0 Then
--some code
cDel = 0;
end if;
end loop;
end;
但是在我的 select 语句中我可以有 null,所以我使用 NVL。另外,因为我可以有数字,所以我需要使用 convert to_char('||v_ret (i).col||')
。此外,列的类型是数字、RAW、日期等。
我的问题:
NVL还有其他可能性吗?
如果没有,oracle默认转换器有吗? (所有类型都需要是 Varchar2)
如果我对你的问题的理解正确,你想包括 v_ret (i).col 为 NULL 的情况。
如果是这样,您可以尝试在 select 语句中使用以下代码:
WHERE ('||v_ret (i).col||' is null OR '||v_ret (i).col||' = '||v_ret (i).val||')
而不是:
WHERE NVL('||v_ret (i).col||', ''<null>'') in ('''||v_ret (i).val||''', ''<null>'')
作为默认转换器,您可以尝试使用 CAST 函数:https://docs.oracle.com/en/database/oracle/oracle-database/12.2/sqlrf/CAST.html
您可以更改代码来执行以下操作:
v_lstmt := 'SELECT count(*) FROM userB.tableB WHERE id = '''||v_ret (i).id||''''
|| ' and ('||v_ret (i).col||' is null or '||v_ret (i).col||' = :val)';
EXECUTE IMMEDIATE v_lstmt INTO cDel using v_ret (i).val;
检查列是否为空 或 与提供的 val
匹配,并使用绑定变量提供要检查的值以减少解析。
但是这仍然依赖于隐式转换,因此如果您在 table 中有一个日期值,例如您将依赖您的 NLS 设置来转换它以匹配目标 table列类型。
您可以使用 all_tab_columns
视图查找目标列的数据类型,并在绑定之前将 val
显式转换为该类型。一种更复杂但可能更稳健的方法是使用 dbms_sql
作为内部动态 SQL 而不是 execute immediate
.
虽然外部查询似乎不需要是动态的,但您可以这样做:
declare
v_lstmt VARCHAR2(32000);
cDel number;
begin
for rec in (SELECT id, col, val FROM tableA) loop
v_lstmt := 'SELECT count(*) FROM tableB WHERE id = '''||rec.id||''''
|| ' and ('||rec.col||' is null or '||rec.col||' = :val)';
dbms_output.put_line(v_lstmt);
EXECUTE IMMEDIATE v_lstmt INTO cDel using rec.val;
If cDel > 0 Then
--some code
cDel := 0;
end if;
end loop;
end;
/
我正在收集两列 (col & val)。进入第二个select col是其他列的参数,val是该列的值。
declare
TYPE t_my_list is record(id varchar2(1000), col VARCHAR2(4000),val VARCHAR2(4000));
TYPE list_3STR is table of t_my_list;
v_stmt VARCHAR2(32000) := 'SELECT id, col, val FROM userA.tableA';
v_lstmt VARCHAR2(32000);
v_ret list_3STR := list_3STR();
cDel number;
begin
EXECUTE IMMEDIATE v_stmt BULK COLLECT INTO v_ret;
for i in v_ret.first..v_ret.last loop
v_lstmt := 'SELECT count(*) FROM userB.tableB
WHERE NVL('||v_ret (i).col||', ''<null>'') in ('''||v_ret (i).val||''', ''<null>'') and idB = '''||v_ret (i).id||'''';
EXECUTE IMMEDIATE v_lstmt INTO cDel;
If cDel > 0 Then
--some code
cDel = 0;
end if;
end loop;
end;
但是在我的 select 语句中我可以有 null,所以我使用 NVL。另外,因为我可以有数字,所以我需要使用 convert to_char('||v_ret (i).col||')
。此外,列的类型是数字、RAW、日期等。
我的问题:
NVL还有其他可能性吗?
如果没有,oracle默认转换器有吗? (所有类型都需要是 Varchar2)
如果我对你的问题的理解正确,你想包括 v_ret (i).col 为 NULL 的情况。
如果是这样,您可以尝试在 select 语句中使用以下代码:
WHERE ('||v_ret (i).col||' is null OR '||v_ret (i).col||' = '||v_ret (i).val||')
而不是:
WHERE NVL('||v_ret (i).col||', ''<null>'') in ('''||v_ret (i).val||''', ''<null>'')
作为默认转换器,您可以尝试使用 CAST 函数:https://docs.oracle.com/en/database/oracle/oracle-database/12.2/sqlrf/CAST.html
您可以更改代码来执行以下操作:
v_lstmt := 'SELECT count(*) FROM userB.tableB WHERE id = '''||v_ret (i).id||''''
|| ' and ('||v_ret (i).col||' is null or '||v_ret (i).col||' = :val)';
EXECUTE IMMEDIATE v_lstmt INTO cDel using v_ret (i).val;
检查列是否为空 或 与提供的 val
匹配,并使用绑定变量提供要检查的值以减少解析。
但是这仍然依赖于隐式转换,因此如果您在 table 中有一个日期值,例如您将依赖您的 NLS 设置来转换它以匹配目标 table列类型。
您可以使用 all_tab_columns
视图查找目标列的数据类型,并在绑定之前将 val
显式转换为该类型。一种更复杂但可能更稳健的方法是使用 dbms_sql
作为内部动态 SQL 而不是 execute immediate
.
虽然外部查询似乎不需要是动态的,但您可以这样做:
declare
v_lstmt VARCHAR2(32000);
cDel number;
begin
for rec in (SELECT id, col, val FROM tableA) loop
v_lstmt := 'SELECT count(*) FROM tableB WHERE id = '''||rec.id||''''
|| ' and ('||rec.col||' is null or '||rec.col||' = :val)';
dbms_output.put_line(v_lstmt);
EXECUTE IMMEDIATE v_lstmt INTO cDel using rec.val;
If cDel > 0 Then
--some code
cDel := 0;
end if;
end loop;
end;
/