2009-06-04 41 views
158

OracleのNVLとCoalesceの間に明白な違いはありませんか?Oracle NVLとCoalesceの相違点

明白な違いは、合体がそのパラメータリスト内の最初の非ヌル項目を返す一方、nvlは2つのパラメータしか取らず、それがヌルでなければ最初のものを返し、それ以外の場合は秒を返します。

NVLはちょうどCOALESCEの「基本ケース」バージョンであってもよいことらしい。

私は何かが足りないのですか?

+0

詳細を確認します。https:/ /jonathanlewis.wordpress.com/2018/02/13/coalesce-v-nvl/ –

答えて

249

COALESCEANSI-92標準の一部であり、より現代的な機能です。

NVLがどの規格があった前に、それは80年代に導入されたOracle固有のものです。2つの値の場合は

、彼らは同義語であります。

ただし、実装方法は異なります。

NVLそれが最初の非NULLを見つけるたびCOALESCEは通常、(このようなシーケンスNEXTVALなど、いくつかの例外が存在する)の評価を停止している間は常に、両方の引数を評価します。

SELECT SUM(val) 
FROM (
     SELECT NVL(1, LENGTH(RAWTOHEX(SYS_GUID()))) AS val 
     FROM dual 
     CONNECT BY 
       level <= 10000 
     ) 

これは、以来、ほとんど0.5秒間動作します1NULLではないにもかかわらず、SYS_GUID()を生成します。

SELECT SUM(val) 
FROM (
     SELECT COALESCE(1, LENGTH(RAWTOHEX(SYS_GUID()))) AS val 
     FROM dual 
     CONNECT BY 
       level <= 10000 
     ) 

これは1NULLではなく、第二引数を評価しないことを理解しています。

SYS_GUIDは生成されず、クエリはインスタントです。以下は、

select nvl('a',sysdate) from dual; 

COALESCEは、一貫性のあるデータ型を期待するエラーしないように

+2

よろしくお願い致します。私はいくつかの種類のトリックがあったと推測していました。 –

+6

これはまったく同義語ではありません...少なくとも、指定された値が異なる型の場合、NVLが暗黙のデータ型キャストを行うという点で違いがあります。たとえば、COALESCEを使用して2つのNULL値(明示的に設定されたものとNUMBER型のデータベースの列から取得されたもの)を渡してエラーが発生しましたが、関数をNVLに変更するだけで消えます。 – DanielM

152

NVLは、最初のパラメータのデータ型への暗黙的な変換を行います。

select coalesce('a',sysdate) from dual; 

は違いもあり

15

「を一貫性のないデータ型エラー」スローされます計画の取り扱いです。

索引付きの列と比較した結果が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に行きます。

3

しかし、これは明白であり、この質問をしたTom氏の言い方でも言及されていますが。しかし、再び立ち上げることができます。

NVLには2つの引数しか指定できません。持っているかもしれCOALESCE以上2.

select nvl('','',1) from dual; //結果:ORA-00909:無効な引数の数
select coalesce('','','1') from dual; //出力:リターン1

13
NVLとCOALESCEは、デフォルト値を提供するのと同じ機能を達成するために使用されている

列がNULLを返す場合

違いは次のとおり

  1. NVLはCOALESCE一方のみ2引数は
  2. NVL引数とCOALESCEがNULL値の最初 発生時停止の両方を評価複数 の引数を取ることができ受け付けます。
  3. NVLは、最初の引数 に基づいて暗黙のデータ型変換を行います。 COALESCEは、すべての引数が同じデータ型であると想定しています。
  4. COALESCEでは、UNION句を使用するクエリで問題が発生します。例 以下
  5. COALESCEはANSI標準で、NVLはOracle固有のものです。

3番目のケースの例。他のケースは単純です。

select nvl('abc',10) from dual;は、NVLとして機能します。暗黙的に数値10を文字列に変換します。エラーで失敗します

select coalesce('abc',10) from dual; - 一貫性のないデータ型:CHAR予想は

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 
    ) ; 

が成功で失敗UNIONのユースケースのためNUMBER

例を得ました。

詳細情報:http://www.plsqlinformation.com/2016/04/difference-between-nvl-and-coalesce-in-oracle.html

1

NVL:値がヌルを置き換え。

COALESCE:最初のNULL以外の式を式リストから返します。

表:PRICE_LIST以下

+----------------+-----------+ 
| Purchase_Price | Min_Price | 
+----------------+-----------+ 
| 10    | null  | 
| 20    |   | 
| 50    | 30  | 
| 100   | 80  | 
| null   | null  | 
+----------------+-----------+ 

は、すべての製品に10%の利益を追加することで

[1]セット販売価格の一例です。
[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で、我々はすべての3つのルールを達成することができますを達成することができることを見ることができます。

+0

NVL(Purchase_Price +(Purchase_Price * 0.10)、nvl(Min_Price、50))についてあなたが言うもの。または:約nvl(NVL(Purchase_Price +(Purchase_Price * 0.10)、Min_Price)、50) ':) –

+0

これは速く、パフォーマンス上の賢明な何を使うべきですか?何千ものレコードを読み込むことを考えていますか? – rickyProgrammer

3

実際、私は各明細書に同意することはできません。

"COALESCEは、すべての引数が同じデータ型であることを期待しています。

これは間違っています。下記を参照してください。引数は異なるデータ型、つまりdocumentedでもかまいません。exprのすべてが数値データ型または数値データ型に暗黙的に変換できる非数値データ型の場合、Oracle Databaseは数字の優先順位が最も高い引数を決定し、暗黙的に残りの引数をそのデータ型に変換し、そのデータ型を返します。。実際には、これは "COALESCEがNull以外の値の最初の発生時に停止する"という共通の表現とは矛盾しています。そうでなければ、テストケースNo.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! 
+1

Re:*テスト4は、 "COALESCEが最初の非ヌル値で評価を停止する" *と矛盾します。同意しません。テスト4は、コンパイラがCOALESCEとのデータ型の一貫性をチェックすることを示しています。最初の非null値で停止することは、実行時の問題であり、コンパイル時の問題ではありません。コンパイル時に、コンパイラは3番目の値がNULLでないことを認識しません。たとえその4番目の値が決して実際に評価されなくても、4番目の引数は正しいデータ型であると主張しています。 – mathguy

1

(合体もう一つの証拠は)最初の非ヌル値で評価を停止しない:

SELECT COALESCE(1, my_sequence.nextval) AS answer FROM dual; 

を実行し、この後、ここにmy_sequence.currval;

関連する問題