226

OracleのNVLとCoalesceの間に明らかな違いはありますか?

明らかな違いは、colesceがパラメータリストの最初の非nullアイテムを返すのに対し、nvlは2つのパラメータのみを取り、nullでない場合は最初のパラメータを返します。それ以外の場合は2番目のパラメータを返します。

NVLは合体の「ベースケース」バージョンにすぎないようです。

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

4

8 に答える 8

331

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

NVLOracle具体的には、標準が存在する前ので導入されました80

2つの値の場合、それらは同義語です。

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

NVL常に両方の引数を評価しますが、COALESCE通常、最初の非引数が見つかると評価を停止しますNULL(シーケンスなどのいくつかの例外がありますNEXTVAL)。

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

これは、ではなくても'sを生成するため、ほぼ0.5数秒間実行されます。SYS_GUID()1NULL

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

1これは、それがaではないことを理解しNULL、2番目の引数を評価しません。

SYS_GUIDは生成されず、クエリは即座に実行されます。

于 2009-06-04T12:03:35.287 に答える
183

NVLは最初のパラメーターのデータ型に暗黙的に変換するため、以下のエラーは発生しません。

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

COALESCEは、一貫したデータ型を期待しています。

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

'一貫性のないデータ型エラー'をスローします

于 2009-06-05T05:13:19.827 に答える
30

NVLとCOALESCEは、列がNULLを返した場合にデフォルト値を提供するという同じ機能を実現するために使用されます。

違いは次のとおりです。

  1. NVLは2つの引数のみを受け入れますが、COALESCEは複数の引数を取ることができます
  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が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

于 2016-01-16T18:06:51.180 に答える
18

プランの取り扱いにも違いがあります。

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に移動します。

于 2014-10-07T18:15:18.587 に答える
6

Coalesce()が最初のnull以外の値で評価を停止しないという別の証拠:

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

これを実行してから、my_sequence.currval;

于 2018-02-13T18:16:16.060 に答える
5

NVL: nullを値に置き換えます。

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

テーブル: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を使用すると、3つのルールすべてを達成できます。

于 2016-01-29T09:34:20.367 に答える
4

実際、私はそれぞれの声明に同意することはできません。

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

これは間違っています。以下を参照してください。引数は異なるデータ型にすることができ、これも文書化されています。exprのすべてのオカレンスが数値データ型、または暗黙的に数値データ型に変換できる非数値データ型である場合、Oracle Databaseは、数値の優先順位が最も高い引数を暗黙的に決定します。残りの引数をそのデータ型に変換し、そのデータ型を返します。。実際、これは一般的な表現「COALESCEはNull以外の値の最初の出現で停止する」と矛盾します。そうでない場合、テストケースNo.4でエラーが発生することはありません。

また、テストケースNo. 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!
于 2016-11-30T08:50:17.963 に答える
3

これは明らかですが、この質問をしたトムが立てた方法でさえ言及されています。しかし、もう一度我慢しましょう。

NVLは2つの引数しか持てません。Coalesceには2つ以上ある場合があります。

select nvl('','',1) from dual;//結果::ORA-00909引数の数が無効です
select coalesce('','','1') from dual; //出力:1を返します

于 2014-11-19T05:28:00.853 に答える