OracleのNVLとCoalesceの間に明白な違いはありませんか?Oracle NVLとCoalesceの相違点
明白な違いは、合体がそのパラメータリスト内の最初の非ヌル項目を返す一方、nvlは2つのパラメータしか取らず、それがヌルでなければ最初のものを返し、それ以外の場合は秒を返します。
NVLはちょうどCOALESCEの「基本ケース」バージョンであってもよいことらしい。
私は何かが足りないのですか?
OracleのNVLとCoalesceの間に明白な違いはありませんか?Oracle NVLとCoalesceの相違点
明白な違いは、合体がそのパラメータリスト内の最初の非ヌル項目を返す一方、nvlは2つのパラメータしか取らず、それがヌルでなければ最初のものを返し、それ以外の場合は秒を返します。
NVLはちょうどCOALESCEの「基本ケース」バージョンであってもよいことらしい。
私は何かが足りないのですか?
COALESCE
ANSI-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
秒間動作します1
がNULL
ではないにもかかわらず、SYS_GUID()
を生成します。
SELECT SUM(val)
FROM (
SELECT COALESCE(1, LENGTH(RAWTOHEX(SYS_GUID()))) AS val
FROM dual
CONNECT BY
level <= 10000
)
これは1
はNULL
ではなく、第二引数を評価しないことを理解しています。
SYS_GUID
は生成されず、クエリはインスタントです。以下は、
select nvl('a',sysdate) from dual;
COALESCEは、一貫性のあるデータ型を期待するエラーしないように
よろしくお願い致します。私はいくつかの種類のトリックがあったと推測していました。 –
これはまったく同義語ではありません...少なくとも、指定された値が異なる型の場合、NVLが暗黙のデータ型キャストを行うという点で違いがあります。たとえば、COALESCEを使用して2つのNULL値(明示的に設定されたものとNUMBER型のデータベースの列から取得されたもの)を渡してエラーが発生しましたが、関数をNVLに変更するだけで消えます。 – DanielM
NVLは、最初のパラメータのデータ型への暗黙的な変換を行います。
select coalesce('a',sysdate) from dual;
は違いもあり
「を一貫性のないデータ型エラー」スローされます計画の取り扱いです。
索引付きの列と比較した結果が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に行きます。
しかし、これは明白であり、この質問をしたTom氏の言い方でも言及されていますが。しかし、再び立ち上げることができます。
NVLには2つの引数しか指定できません。持っているかもしれCOALESCE以上2.
select nvl('','',1) from dual;
//結果:ORA-00909
:無効な引数の数
select coalesce('','','1') from dual;
//出力:リターン1
列がNULLを返す場合
違いは次のとおり
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
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つのルールを達成することができますを達成することができることを見ることができます。
NVL(Purchase_Price +(Purchase_Price * 0.10)、nvl(Min_Price、50))についてあなたが言うもの。または:約nvl(NVL(Purchase_Price +(Purchase_Price * 0.10)、Min_Price)、50) ':) –
これは速く、パフォーマンス上の賢明な何を使うべきですか?何千ものレコードを読み込むことを考えていますか? – rickyProgrammer
実際、私は各明細書に同意することはできません。
"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!
Re:*テスト4は、 "COALESCEが最初の非ヌル値で評価を停止する" *と矛盾します。同意しません。テスト4は、コンパイラがCOALESCEとのデータ型の一貫性をチェックすることを示しています。最初の非null値で停止することは、実行時の問題であり、コンパイル時の問題ではありません。コンパイル時に、コンパイラは3番目の値がNULLでないことを認識しません。たとえその4番目の値が決して実際に評価されなくても、4番目の引数は正しいデータ型であると主張しています。 – mathguy
(合体もう一つの証拠は)最初の非ヌル値で評価を停止しない:
SELECT COALESCE(1, my_sequence.nextval) AS answer FROM dual;
を実行し、この後、ここにmy_sequence.currval;
詳細を確認します。https:/ /jonathanlewis.wordpress.com/2018/02/13/coalesce-v-nvl/ –