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 null
和x 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:任何 + 为空的主要内容,如果未能解决你的问题,请参考以下文章