Oracle SQL:任何 + 为空

Posted

技术标签:

【中文标题】Oracle SQL:任何 + 为空【英文标题】:Oracle SQL: ANY + IS NULL 【发布时间】:2020-04-30 04:53:29 【问题描述】:

我需要检查几个带有 NULL 的字段。我当然可以使用OR

SELECT * FROM table WHERE f1 IS NULL OR f2 IS NULL OR f3 IS NULL

但是ANY 可以很好地处理逻辑操作。

在 Oracle 的 SQL 中可以做类似的事情吗?

SELECT * FROM table WHERE ANY (f1, f2, f3) IS NULL

我使用 Oracle 12c。

【问题讨论】:

这是个好问题。您的语法看起来不错,但不幸的是,Oracle SQL 不支持。但是,这与 PL/SQL 无关,PL/SQL 是 Oracle 在 DBMS 中的编程语言。这是关于Oracle的SQL。因此,我从您的问题中删除了所有 PL/SQL 引用,并用 SQL 对其进行了标记。 我刚刚检查过其他 DBMS。 mysql、SQL Server 或 PostgreSQL 也不支持这种语法。 @Thorsten Kettner 哦,你是对的。这是关于 SQL 而不是 PLSQL。 坚持is null。 Oracle 可以利用具有or 条件的索引——您通常希望保持该选项处于打开状态。 【参考方案1】:

与 Tim 的分析器相反,您可以使用 GREATEST 或 LEAST 来查看任何值为 NULL 的位置

select * from dual where greatest('a',2,3,null) is null;

【讨论】:

很好的解决方案。我一直认为当其中一个参数为空时,这些函数返回空是一件令人讨厌的事情。但是在这种情况下很方便:-) 这似乎在混合数字和字符串时起作用,因为数字似乎被转换为字符串。但是如果有例如它就行不通了。涉及DATE 列。 我在列表中有 VARCHAR2 字段,它工作正常【参考方案2】:

Oracle 中使用表达式或函数的技巧:

如果这些都是数值,你可以使用+

with t(a, b, c) as (
  select 1, 2, 3 from dual union all 
  select null, 2, 3 from dual union all 
  select null, null, 3 from dual
)
select *
from t
where a + b + c is null;

它产生

A|B|C|
-|-|-|
 |2|3|
 | |3|

另外,可以使用可读性较差的DECODE 函数,或者将GREATEST 用作Gary already showed:

decode(null, a, 1, b, 1, c, 1, 0) = 1;

使用MINUS

您可以使用(a, b, c) = ((a, b, c)) 检查是否没有任何值是NULL,如果谓词产生NULL。不幸的是,由于 Oracle 不知道 BOOLEAN 类型,您不能 NULL 检查谓词本身(并且 LNNVL 似乎不适用于上述条件),但您可以使用 MINUS

with t(a, b, c) as (
  select 1, 2, 3 from dual union all 
  select null, 2, 3 from dual union all 
  select null, null, 3 from dual
)
select *
from t
minus
select *
from t
where (a, b, c) = ((a, b, c)); -- None of the values is NULL

在很多情况下,这显然是一个缓慢的解决方案,所以不好。

标准 SQL:

值得一提的是,标准 SQL(例如,由 PostgreSQL 实现,但不是 Oracle 实现)支持对行值表达式的空谓词,如下所示:

not ((a, b, c) is not null)

“双重否定”是必要的,因为真值表显示not x is nullx is not null 不是同一个东西(source):

+-----------------------+-----------+---------------+---------------+-------------------+
| Expression            | R IS NULL | R IS NOT NULL | NOT R IS NULL | NOT R IS NOT NULL |
+-----------------------+-----------+---------------+---------------+-------------------+
| degree 1: null        | true      | false         | false         |  true             |
| degree 1: not null    | false     | true          | true          |  false            |
| degree > 1: all null  | true      | false         | false         |  true             |
| degree > 1: some null | false     | false         | true          |  true             |
| degree > 1: none null | false     | true          | true          |  false            |
+-----------------------+-----------+---------------+---------------+-------------------+

【讨论】:

谢谢卢卡斯。我有 VARCHAR2 字段,看起来“使用 +”方法也有效。 “标准 SQL”方法给了我一个错误:00920. 00000 - “无效的关系运算符” 您不应将+VARCHAR2 字段一起使用,否则当Oracle 对每个值应用TO_NUMBER() 时,您可能会遇到数字转换错误。在这种情况下,GREATEST() 方法更好,但最好的方法是使用普通的OR 谓词!为了完整起见,我只想添加“标准 SQL”部分 1) 以防 Oracle 曾经实现过该功能,2) 以防有人使用其他 RDBMS 访问此答案。 ? 我已经允许自己修改你的第二种方法:)【参考方案3】:

用行构造器语法比较整行:

SELECT * 
FROM tab 
CROSS APPLY (SELECT CASE WHEN (f1,f2,f3)=((f1,f2,f3)) THEN 1 ELSE 0 END AS all_non_nulls  
             FROM dual) s
WHERE s.all_non_nulls = 0; -- 1 

db<>fiddle demo

(f1,f2,f3) -> 这是列列表

【讨论】:

以上是关于Oracle SQL:任何 + 为空的主要内容,如果未能解决你的问题,请参考以下文章

Oracle中查询某字段不为空的SQL语句怎么写

如何在 Oracle SQL 中查找和过滤同一张表上的数据

oracle SQL语句怎么修改数据表的字段允许为空?

在Oracle中怎么判断字段是不是为空

oracle SQL语句怎么关联一张表 没有对应数据的就显示为空

ORACLE SQL Developer 所需的属性主机名不能为空或为空