NVL और Coalesce के बीच Oracle अंतर


207

क्या Oracle में NVL और Coalesce के बीच गैर स्पष्ट अंतर हैं?

स्पष्ट अंतर यह है कि कोलेस अपनी पैरामीटर सूची में पहला गैर अशक्त आइटम लौटाएगा, जबकि nvl केवल दो पैरामीटर लेता है और यदि यह शून्य नहीं है तो पहला रिटर्न देता है, अन्यथा यह दूसरा रिटर्न देता है।

ऐसा लगता है कि NVL सिर्फ एक 'बेस केस' संस्करण हो सकता है।

क्या मैं कुछ भूल रहा हूँ?


जवाबों:


311

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जनरेट नहीं हुए हैं और क्वेरी तत्काल है।


11
वे बिल्कुल समानार्थी नहीं हैं ... कम से कम आप इस तथ्य में अंतर पा सकते हैं कि एनवीएल एक अंतर्निहित डेटा प्रकार की कास्टिंग करता है यदि दिए गए मान विभिन्न प्रकार के होते हैं। उदाहरण के लिए, मुझे COALESCE का उपयोग करके एक त्रुटि मिल रही थी, इसे दो NULL मान (एक स्पष्ट रूप से सेट और डेटाबेस में एक कॉलम से लिया गया, जैसे NUMBER नंबर), जो केवल फ़ंक्शन को NVL में बदलकर गायब हो जाता है।
डैनियल

170

एनवीएल पहले पैरामीटर के डेटाटाइप के लिए एक अंतर्निहित रूपांतरण करेगा, इसलिए निम्न त्रुटि नहीं करता है

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

COALESCE को लगातार डेटाैटिप्स की उम्मीद है।

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

'असंगत डेटाटाइप त्रुटि' को फेंक देगा


22

स्तंभ NULL को वापस करने की स्थिति में डिफ़ॉल्ट मान प्रदान करने की समान कार्यक्षमता को प्राप्त करने के लिए NVL और COALESCE का उपयोग किया जाता है।

अंतर हैं:

  1. NVL केवल 2 तर्क स्वीकार करता है जबकि COALESCE कई तर्क दे सकता है
  2. एनवीएल एक गैर-मूल्य के पहले घटना पर दोनों तर्कों और COALESCE स्टॉप का मूल्यांकन करता है।
  3. एनवीएल एक अंतर्निहित डेटाटाइप रूपांतरण करता है जो इसे दिए गए पहले तर्क के आधार पर करता है। COALESCE को सभी तर्क एक ही डेटाटाइप के होने की उम्मीद है।
  4. COALESCE उन प्रश्नों में समस्या देता है जो UNION खंड का उपयोग करते हैं। नीचे उदाहरण है
  5. COALESCE ANSI मानक है जहाँ NVL Oracle विशिष्ट है।

तीसरे मामले के उदाहरण। अन्य मामले सरल हैं।

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


मुझे नहीं लगता है कि "यूनियन" के साथ एक विशिष्ट समस्या है, इसलिए ऐसा प्रतीत होता है कि ओरेकल डिफ़ॉल्ट रूप से एक चार्ट में आपको उप-क्वेरी में डाली नल टाइप करना चाहता है और फिर आपके आइटम 3 में सूचीबद्ध एक ही मुद्दा है (मिश्रित डेटा प्रकार)। यदि आप इसे TO_DATE (NULL) में बदलते हैं, तो संभवतः आपको त्रुटि नहीं मिलेगी (मैं Oracle के संस्करण पर त्रुटि को पुन: उत्पन्न नहीं कर सकता हूं जो मैं उपयोग कर रहा हूं)। अन्यथा मैं आपके उत्तर से सहमत हूँ और आपकी सराहना करता हूँ। :-)
छप

17

प्लान हैंडलिंग में भी अंतर है।

जब खोज 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 पर जाते हैं


6

एक और सबूत जो पहले गैर-शून्य मान के साथ जमाव () मूल्यांकन बंद नहीं करता है:

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

इसे चलाएं, फिर जांचें my_sequence.currval;


5

वास्तव में मैं प्रत्येक कथन से सहमत नहीं हो सकता।

"COALESCE को सभी तर्क समान डेटाटाइप के होने की उम्मीद है।"

यह गलत है, नीचे देखें। तर्क अलग-अलग डेटा प्रकार हो सकते हैं, जो कि प्रलेखित भी है : यदि expr की सभी घटनाएँ संख्यात्मक डेटा प्रकार या कोई भी गैर-डेटा डेटा प्रकार हैं, जिन्हें कथित रूप से एक संख्यात्मक डेटा प्रकार में परिवर्तित किया जा सकता है, तो Oracle डेटाबेस तर्क को उच्चतम संख्यात्मक वरीयता के साथ निर्धारित करता है, संक्षेप में शेष तर्कों को उस डेटा प्रकार में परिवर्तित करता है, और उस डेटा प्रकार को वापस करता है। । वास्तव में यह सामान्य अभिव्यक्ति के विपरीत भी है "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!

1
पुन: टेस्ट 4 विरोधाभास "COALESCE पहले गैर-अशक्त मूल्य पर मूल्यांकन बंद कर देता है" । मैं असहमत हूं। परीक्षण 4 दिखाता है कि संकलनकर्ता COALESCE के साथ डेटा प्रकार की स्थिरता के लिए जाँच करता है। पहले गैर-शून्य मान पर रोक एक रनटाइम समस्या है, संकलन-समय समस्या नहीं। संकलन के समय संकलनकर्ता को यह नहीं पता होता है कि तीसरा मान (कहना) गैर-शून्य होगा; यह जोर देकर कहता है कि चौथा तर्क सही डेटा प्रकार का भी है, भले ही उस चौथे मूल्य का वास्तव में मूल्यांकन नहीं किया जाएगा।
मैथुगुए

3

हालांकि यह एक स्पष्ट है, और यहां तक ​​कि टॉम द्वारा लगाए गए तरीके से भी उल्लेख किया गया है जिन्होंने यह सवाल पूछा था। लेकिन फिर से डाल दिया।

NVL में केवल 2 तर्क हो सकते हैं। 2 से अधिक हो सकता है।

select nvl('','',1) from dual;// परिणाम:: ORA-00909अमान्य संख्या के तर्क
select coalesce('','','1') from dual; // आउटपुट: रिटर्न 1


3

एनवीएल: मूल्य के साथ नल को बदलें।

COALESCE: अभिव्यक्ति सूची से पहला गैर-अशक्त अभिव्यक्ति लौटाएं।

तालिका: PRICE_LIST

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

नीचे

सभी उत्पादों में 10% लाभ जोड़ने के साथ बिक्री मूल्य निर्धारित करें।
[२] यदि कोई खरीद सूची मूल्य नहीं है, तो बिक्री मूल्य न्यूनतम मूल्य है। निकासी बिक्री के लिए।
[३] यदि कोई न्यूनतम मूल्य भी नहीं है, तो बिक्री मूल्य को डिफ़ॉल्ट मूल्य "५०" के रूप में निर्धारित करें।

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) :)
फ्लोरिन घिता

जो तेज़ है, प्रदर्शन वार क्या उपयोग किया जाना चाहिए? लोड करने के लिए हजार रिकॉर्ड पर विचार?
राक्यप्रोग्रामर
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.