【问题标题】:what is the alternative way to check for null with out using is null operator in oracle在 oracle 中不使用 is null 运算符来检查 null 的替代方法是什么
【发布时间】:2015-01-15 06:49:24
【问题描述】:

我写了一个存储过程,从一个表中选择(一些列有空数据)并插入到另一个表中而不重复。

我的部分存储过程代码:

 LOOP
   BEGIN
     SELECT ID
       INTO ROWCOUNT
   FROM TBL_EMPLOYEE
 WHERE 

     NAME      = TEMPTABLE.NAME
  AND AGE           =TEMPTABLE.AGE

EXCEPTION
WHEN no_data_found THEN
  ROWCOUNT := 0;
END;
IF ROWCOUNT = 0 THEN
  INSERT INTO TARGET TABLE ......

在上面的代码中,某些列的数据为空(例如:TEMPTABLE.AGE 等)。 当有空值时,它会抛出 no_data_found 异常并插入数据。我们也尝试过放置 nvl 函数,这需要更多时间。

LOOP
BEGIN
  SELECT ID
  INTO ROWCOUNT
  FROM TBL_EMPLOYEE
 WHERE 

     nvl(NAME,0000)      = nvl(TEMPTABLE.NAME,0000)
  AND nvl(AGE,0000)           =nvl(TEMPTABLE.AGE,0000)

EXCEPTION
WHEN no_data_found THEN
  ROWCOUNT := 0;
END;
IF ROWCOUNT = 0 THEN
  INSERT INTO TARGET TABLE ......

任何人都可以建议任何替代方法如何使用等于运算符进行空检查。 我也用 LIKE 试过了,但是没用。

【问题讨论】:

  • 为什么你不想使用空检查?
  • 我想使用的是空值,但是当没有数据时它会作为空值出现。但是当有数据时,它应该用“=”检查。如有错误请指正。
  • 我也尝试使用 LIKE,但无法检查 null。有什么想法吗?
  • 你为什么不一直使用 nvl?不检查异常,或者我不明白你的问题
  • 嗨@Dom84,我一直在尝试它,但是,它正在达到性能。我必须像这样处理超过 20k 条记录,它本身在 2k 条记录中失败/超时。

标签: sql oracle plsql


【解决方案1】:

您以错误的方式进行检查。完全消除ROWCOUNT 变量和循环并使用NOT EXISTS()

BEGIN
  INSERT INTO TARGET_TABLE
  SELECT .....
  FROM DUAL 
  WHERE NOT EXISTS (
    SELECT *
    FROM TBL_EMPLOYEE
    WHERE nvl(NAME,0000) = nvl(TEMPTABLE.NAME,0000)
    AND nvl(AGE,0000) = nvl(TEMPTABLE.AGE,0000);
END

并且您的条件可能有错误:如果您的意图是将两个空值视为“相等”,请将条件更改为:

WHERE (NAME = TEMPTABLE.NAME OR NVL(NAME, TEMPTABLE.NAME) IS NULL)
AND (AGE = TEMPTABLE.AGE OR NVL(AGE, TEMPTABLE.AGE) IS NULL)

【讨论】:

    【解决方案2】:

    我想你想这样做:

    NAME = VALUE {in case of Some Value}
    

    NAME IS NULL {in case the value is null}
    

    ORACLE 不会自己处理它。我认为这是一个合乎逻辑的条件,应该合乎逻辑地处理。如果我的回答/理解正确,请告诉我?

    【讨论】:

    • 感谢最后我通过检查 if 和 else 块来处理存储过程中的查询字符串。
    【解决方案3】:

    替换

    nvl(NAME,0000) = nvl(TEMPTABLE.NAME,0000)
    

    (NAME is NULL and TEMPTABLE.NAME is null or NAME = TEMPTABLE.NAME)
    

    【讨论】:

    • 对不起!不走运 :( 得到这个错误 :ORA-01422: 精确提取返回的行数超过了请求的行数
    • @Madhu sudhan Reddy 你放括号了吗?因为我给了你条件的几乎等效版本(如果名称为 null 并且 temptable.name = 0,你的条件也将返回 true)
    • @MadhusudhanReddy 错误消息是自我描述的。它应该只检索一行。你想要count(ID) 吗?
    • @Multisync : 我用的和你上面提到的完全一样。但还是不行。
    • @MaheswaranRavisankar:是的,我只需要一行。但是如果有更多记录,计数功能会花费更多时间。
    【解决方案4】:

    尝试用最简单的术语解释您想要完成的任务。你给出了一组令人困惑的要求,并且抛出了一些代码,无论如何,这些代码可能会让我们走上错误的轨道。可能您需要的内容可以在一个语句中完成,而无需循环。一些尝试:

    删除由某些键列 [name,age] 的重复项,这些键列由另一个值区分。

    INSERT INTO target (name,age,other_value1,other_value2)
    SELECT
      name, age,other_value1,other_value2
    FROM (
      SELECT
        name,
        age,
        other_value1,
        other_value2,
        ROW_NUMBER() OVER (PARTITION BY name,age ORDER BY other_value1) rn
      FROM source
      ) WHERE rn = 1
    

    区别列可以是输入数据时的时间戳,您可以使用ROW_NUMBER() OVER (PARTITION BY name,age ORDER BY time_entered DESC) rn 之类的东西来保留最新记录。

    根据所有列删除重复项

    INSERT INTO target (name,age,other_value1,other_value2)
    SELECT
      name, age,other_value1,other_value2
    FROM source
    GROUP BY name,age,other_value1,other_value2
    

    【讨论】:

      【解决方案5】:
      BEGIN
        SELECT ID
        INTO ROWCOUNT
        FROM TBL_EMPLOYEE
       WHERE decode(NAME,TEMPTABLE.NAME,1)=1
         AND decode(AGE,TEMPTABLE.AGE,1)=1
      EXCEPTION
      WHEN no_data_found THEN
        ROWCOUNT := 0;
      END;
      

      它适用于任何简单的数据类型 - 数字 varchar2、日期等。

      【讨论】:

      • 对于较少的行数,它可以正常工作,例如:
      • 这取决于...显然它不使用您的 b*tree 索引并使用全表扫描。您可能需要考虑类似这样的功能索引: created index indx1 on tnl_employee on(nvl(NAME, '{null}'));然后在查询中使用以下表达式: nvl(name, '{name}') = nvl(temptable.name, '{null}') 或者您可以考虑位图索引,但要记住锁...
      【解决方案6】:

      我的解决办法是:

      从 TBL_EMPLOYEE WHERE 中选择姓名、年龄 NAME = '你的名字' AND ( (AGE = yourAge) OR (AGE IS NULL AND yourAge 为 NULL) )

      这里 NAME 和 AGE 是表列名。 'yourName' 和 'yourAge' 是传递的运行时值。

      如果它不适合你,请告诉我。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2012-11-21
        • 1970-01-01
        • 2011-05-22
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2017-12-19
        相关资源
        最近更新 更多