【问题标题】:Looking NULL values for different Oracle Type寻找不同 Oracle 类型的 NULL 值
【发布时间】:2019-01-11 01:07:06
【问题描述】:

我正在收集两列(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;

但是在我的选择语句中我可以有 null 所以我使用 NVL。另外,因为我可以有号码,所以我需要使用转换to_char('||v_ret (i).col||')。此外,列的类型是数字、RAW、日期等。

我的问题:

  • 除了NVL还有其他可能性吗?

  • 如果没有,有 oracle 默认转换器吗? (所有类型都需要Varchar2)

【问题讨论】:

  • Please post text rather than images。并包括您当前看到的结果,以及如果它们不同,您想看到什么。您的 null 处理是否应该说目标列可以为 null 或与目标 val 匹配?

标签: sql oracle plsql null nvl


【解决方案1】:

你可以改变你的代码来做:

   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匹配,并使用绑定变量提供值以检查以减少解析。

但是这仍然依赖于隐式转换,因此如果您在表中有日期值,例如,您将依赖 NLS 设置将其转换为与目标表列类型匹配。

您可以使用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;
/

【讨论】:

  • thnak 你,没关系,但是如果两个站点都为 null 怎么办? ** v_ret (i).val** 所以我需要将 null 与 null 进行比较...怎么做?
  • 什么意思?如果tablea.val 为空?如果是这样,那在tableb 中应该匹配什么?如果目标列为空,它现在仍然会匹配,来自rec.col is null?
  • tableA - for id10, colAAAA, val is null.....现在等于这个 null 与 tableB - id10, AAAA = null....如何比较它?结果对我来说需要是 1
  • 答案中的查询计算结果为and (AAAA is null or AAAA = :val),以便匹配。 (没有什么等于或不等于null,所以你必须使用is null)。
  • :val 是绑定变量占位符,不能用双引号。
【解决方案2】:

如果我正确理解了您的问题,您希望包括 v_ret (i).col 为 NULL 的情况。

如果是这样,您可以尝试在您的选择语句中使用以下代码:

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

【讨论】:

  • 链接到the Oracle RDBMS docs 可能更有用 *8-) 你仍然需要知道要转换为哪种数据类型。
  • @AlexPoole 哈哈,真的! :D
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2016-03-12
  • 1970-01-01
  • 2013-04-15
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多