답변:
COALESCE
ANSI-92
표준 의 일부인보다 현대적인 기능입니다 .
NVL
이다 Oracle
그것은에 도입 된 특정 80
어떤 기준이되기 전에 S '이 (가) 있습니다.
두 값의 경우 동의어입니다.
그러나 그것들은 다르게 구현됩니다.
NVL
항상 두 인수를 모두 평가하지만 COALESCE
일반적으로 첫 번째가 아닌 것을 발견 할 때마다 평가를 중지합니다 NULL
(sequence와 같은 예외가 있습니다 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 및 COALESCE는 컬럼이 NULL을 리턴하는 경우 기본값을 제공하는 동일한 기능을 달성하는 데 사용됩니다.
차이점은 다음과 같습니다.
세 번째 사례의 예입니다. 다른 경우는 간단합니다.
select nvl('abc',10) from dual;
NVL이 숫자 10을 문자열로 암시 적으로 변환하므로 작동합니다.
select coalesce('abc',10) from dual;
일관되지 않은 데이터 유형 : CHAR에 NUMBER 번이 있습니다.
UNION 사용 사례의 예
SELECT COALESCE(a, sysdate)
from (select null as a from dual
union
select null as a from dual
);
실패 ORA-00932: inconsistent datatypes: expected CHAR got DATE
SELECT NVL(a, sysdate)
from (select null as a from dual
union
select null as a from dual
) ;
성공합니다.
자세한 정보 : http://www.plsqlinformation.com/2016/04/difference-between-nvl-and-coalesce-in-oracle.html
계획 처리에도 차이가 있습니다.
Oracle은 검색 nvl
결과와 색인 열을 비교할 때 분기 필터를 연결하여 최적화 된 계획을 구성 할 수 있습니다 .
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 로 이동 하십시오 .
사실 나는 각 진술에 동의 할 수 없습니다.
"COALESCE는 모든 인수가 동일한 데이터 유형이어야합니다."
이것은 잘못입니다. 아래를 참조하십시오. 인수는 다른 데이터 유형일 수 있으며 문서화됩니다 . expr의 모든 항목이 숫자 데이터 유형이거나 숫자 데이터 유형으로 내재적으로 변환 될 수있는 숫자가 아닌 데이터 유형 인 경우 Oracle Database는 가장 높은 숫자 우선 순위를 갖는 인수를 내재적으로 판별합니다. 나머지 인수를 해당 데이터 유형으로 변환하고 해당 데이터 유형을 리턴합니다. . 실제로 이것은 일반 표현식 "Null이 아닌 값이 처음 발생할 때 COALESCE가 중지됨"과 모순됩니다. 그렇지 않으면 테스트 케이스 4가 오류를 발생시키지 않아야합니다.
또한 테스트 사례 번호 5에 따르면 COALESCE
암시적인 인수 변환이 수행됩니다.
DECLARE
int_val INTEGER := 1;
string_val VARCHAR2(10) := 'foo';
BEGIN
BEGIN
DBMS_OUTPUT.PUT_LINE( '1. NVL(int_val,string_val) -> '|| NVL(int_val,string_val) );
EXCEPTION WHEN OTHERS THEN DBMS_OUTPUT.PUT_LINE('1. NVL(int_val,string_val) -> '||SQLERRM );
END;
BEGIN
DBMS_OUTPUT.PUT_LINE( '2. NVL(string_val, int_val) -> '|| NVL(string_val, int_val) );
EXCEPTION WHEN OTHERS THEN DBMS_OUTPUT.PUT_LINE('2. NVL(string_val, int_val) -> '||SQLERRM );
END;
BEGIN
DBMS_OUTPUT.PUT_LINE( '3. COALESCE(int_val,string_val) -> '|| COALESCE(int_val,string_val) );
EXCEPTION WHEN OTHERS THEN DBMS_OUTPUT.PUT_LINE('3. COALESCE(int_val,string_val) -> '||SQLERRM );
END;
BEGIN
DBMS_OUTPUT.PUT_LINE( '4. COALESCE(string_val, int_val) -> '|| COALESCE(string_val, int_val) );
EXCEPTION WHEN OTHERS THEN DBMS_OUTPUT.PUT_LINE('4. COALESCE(string_val, int_val) -> '||SQLERRM );
END;
DBMS_OUTPUT.PUT_LINE( '5. COALESCE(SYSDATE,SYSTIMESTAMP) -> '|| COALESCE(SYSDATE,SYSTIMESTAMP) );
END;
Output:
1. NVL(int_val,string_val) -> ORA-06502: PL/SQL: numeric or value error: character to number conversion error
2. NVL(string_val, int_val) -> foo
3. COALESCE(int_val,string_val) -> 1
4. COALESCE(string_val, int_val) -> ORA-06502: PL/SQL: numeric or value error: character to number conversion error
5. COALESCE(SYSDATE,SYSTIMESTAMP) -> 2016-11-30 09:55:55.000000 +1:0 --> This is a TIMESTAMP value, not a DATE value!
NVL : 널을 값으로 바꾸십시오 .
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(Purchase_Price + (Purchase_Price * 0.10), nvl(Min_Price,50))
. 또는 : nvl(NVL(Purchase_Price + (Purchase_Price * 0.10), Min_Price) ,50)
:)