Oracle中的NVL和Coalesce之间是否存在不明显的差异?
明显的区别是coalesce将返回其参数列表中的第一个非空项,而nvl只接受两个参数,如果第一个参数不为空则返回第一个,否则返回第二个。
看来NVL可能只是联合的“基本情况”版本。
我遗漏了什么吗?
Oracle中的NVL和Coalesce之间是否存在不明显的差异?
明显的区别是coalesce将返回其参数列表中的第一个非空项,而nvl只接受两个参数,如果第一个参数不为空则返回第一个,否则返回第二个。
看来NVL可能只是联合的“基本情况”版本。
我遗漏了什么吗?
当前回答
NVL将隐式转换为第一个参数的数据类型,因此下面的操作不会出错
select nvl('a',sysdate) from dual;
COALESCE期望一致的数据类型。
select coalesce('a',sysdate) from dual;
将抛出'不一致的数据类型错误'
其他回答
另一个coalesce()不停止对第一个非空值求值的证明:
SELECT COALESCE(1, my_sequence.nextval) AS answer FROM dual;
运行这个,然后检查my_sequence.currval;
COALESCE是更现代的函数,是ANSI-92标准的一部分。
NVL是Oracle特有的,它是在80年代引入的,当时还没有任何标准。
如果有两个值,则它们是同义词。
但是,它们的实现方式不同。
NVL总是计算这两个参数,而COALESCE通常在发现第一个非null时停止计算(有一些例外,比如序列NEXTVAL):
SELECT SUM(val)
FROM (
SELECT NVL(1, LENGTH(RAWTOHEX(SYS_GUID()))) AS val
FROM dual
CONNECT BY
level <= 10000
)
这将运行大约0.5秒,因为它会生成SYS_GUID(),尽管1不是NULL。
SELECT SUM(val)
FROM (
SELECT COALESCE(1, LENGTH(RAWTOHEX(SYS_GUID()))) AS val
FROM dual
CONNECT BY
level <= 10000
)
它理解1不是NULL,并且不计算第二个参数。
SYS_GUID不会生成,查询是即时的。
NVL将隐式转换为第一个参数的数据类型,因此下面的操作不会出错
select nvl('a',sysdate) from dual;
COALESCE期望一致的数据类型。
select coalesce('a',sysdate) from dual;
将抛出'不一致的数据类型错误'
NVL:将null替换为value。
COALESCE:从表达式列表中返回第一个非空表达式。
表:PRICE_LIST
+----------------+-----------+
| Purchase_Price | Min_Price |
+----------------+-----------+
| 10 | null |
| 20 | |
| 50 | 30 |
| 100 | 80 |
| null | null |
+----------------+-----------+
的例子如下 [1]设定销售价格,所有产品增加10%利润。 [2]如果没有进货目录价格,则销售价格为最低价。清仓甩卖。 [3]如果也没有最低价格,则将销售价格设置为默认价格“50”。
SELECT
Purchase_Price,
Min_Price,
NVL(Purchase_Price + (Purchase_Price * 0.10), Min_Price) AS NVL_Sales_Price,
COALESCE(Purchase_Price + (Purchase_Price * 0.10), Min_Price,50) AS Coalesce_Sales_Price
FROM
Price_List
用现实生活中的实例解释。
+----------------+-----------+-----------------+----------------------+
| Purchase_Price | Min_Price | NVL_Sales_Price | Coalesce_Sales_Price |
+----------------+-----------+-----------------+----------------------+
| 10 | null | 11 | 11 |
| null | 20 | 20 | 20 |
| 50 | 30 | 55 | 55 |
| 100 | 80 | 110 | 110 |
| null | null | null | 50 |
+----------------+-----------+-----------------+----------------------+
你可以看到,使用NVL,我们可以实现规则[1],[2],但使用COALSECE,我们可以实现所有三个规则。
在计划处理方面也有不同。
当搜索包含nvl结果与索引列的比较时,Oracle可以通过串联分支过滤器形成优化计划。
create table tt(a, b) as
select level, mod(level,10)
from dual
connect by level<=1e4;
alter table tt add constraint ix_tt_a primary key(a);
create index ix_tt_b on tt(b);
explain plan for
select * from tt
where a=nvl(:1,a)
and b=:2;
explain plan for
select * from tt
where a=coalesce(:1,a)
and b=:2;
nvl:
-----------------------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
-----------------------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 2 | 52 | 2 (0)| 00:00:01 |
| 1 | CONCATENATION | | | | | |
|* 2 | FILTER | | | | | |
|* 3 | TABLE ACCESS BY INDEX ROWID| TT | 1 | 26 | 1 (0)| 00:00:01 |
|* 4 | INDEX RANGE SCAN | IX_TT_B | 7 | | 1 (0)| 00:00:01 |
|* 5 | FILTER | | | | | |
|* 6 | TABLE ACCESS BY INDEX ROWID| TT | 1 | 26 | 1 (0)| 00:00:01 |
|* 7 | INDEX UNIQUE SCAN | IX_TT_A | 1 | | 1 (0)| 00:00:01 |
-----------------------------------------------------------------------------------------
Predicate Information (identified by operation id):
---------------------------------------------------
2 - filter(:1 IS NULL)
3 - filter("A" IS NOT NULL)
4 - access("B"=TO_NUMBER(:2))
5 - filter(:1 IS NOT NULL)
6 - filter("B"=TO_NUMBER(:2))
7 - access("A"=:1)
合并:
---------------------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
---------------------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 1 | 26 | 1 (0)| 00:00:01 |
|* 1 | TABLE ACCESS BY INDEX ROWID| TT | 1 | 26 | 1 (0)| 00:00:01 |
|* 2 | INDEX RANGE SCAN | IX_TT_B | 40 | | 1 (0)| 00:00:01 |
---------------------------------------------------------------------------------------
Predicate Information (identified by operation id):
---------------------------------------------------
1 - filter("A"=COALESCE(:1,"A"))
2 - access("B"=TO_NUMBER(:2))
请访问http://www.xt-r.com/2012/03/nvl-coalesce-concatenation.html。