2009-06-04 14 views
158

क्या ओरेकल में एनवीएल और कोलेसे के बीच कोई स्पष्ट अंतर नहीं है?एनवीएल और कोलेसेस के बीच ओरेकल मतभेद

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

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

मैं कुछ याद आ रही है?

+0

अधिक यहाँ: https://jonathanlewis.wordpress.com/2018/02/13/coalesce-v-nvl/ –

उत्तर

249

COALESCE और अधिक आधुनिक समारोह है कि ANSI-92 मानक का एक हिस्सा है।

NVLOracle विशिष्ट है, इसे 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 सेकंड के लिए चलाता है, के बाद से यह 1NULL नहीं होने के बावजूद 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 उत्पन्न नहीं हुए हैं और क्वेरी तत्काल है।

+2

बहुत बढ़िया, धन्यवाद। मैं अनुमान लगा रहा था कि कुछ प्रकार की चाल थी। –

+6

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

152

तो निम्न त्रुटि नहीं है

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

COALESCE 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

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

एनवीएल में केवल 2 तर्क हो सकते हैं। सम्मिलित हो सकता है और अधिक से अधिक 2.

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

13

NVL और COALESCE एक डिफ़ॉल्ट मान प्रदान करने की ही कार्यक्षमता प्राप्त करने के लिए उपयोग किया जाता है यदि कॉलम एक पूर्ण लौटाता है।

अंतर हैं:

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

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

select nvl('abc',10) from dual; काम करेगा क्योंकि एनवीएल संख्यात्मक 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 
    ) ; 

सफल होता है विफल रहता है।

अधिक जानकारी: http://www.plsqlinformation.com/2016/04/difference-between-nvl-and-coalesce-in-oracle.html

1

NVL: मूल्य के साथ अशक्त बदलें।

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

तालिका: 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 साथ हम सभी तीन नियमों को प्राप्त कर सकते प्राप्त कर सकते हैं।

+0

आप 'एनवीएल (खरीद_Price + (खरीद_Price * 0.10), nvl (Min_Price, 50)) के बारे में क्या कहते हैं। या इसके बारे में: 'nvl (एनवीएल (खरीद_Price + (खरीद_Price * 0.10), Min_Price), 50)' :) –

+0

जो तेज़ है, प्रदर्शन के अनुसार क्या उपयोग किया जाना चाहिए? लोड करने के लिए हजारों रिकॉर्ड पर विचार? – rickyProgrammer

3

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

"COALESCE सभी तर्कों को एक ही डेटाटाइप के होने की अपेक्षा करता है।"

यह गलत है, नीचे देखें। तर्क विभिन्न डेटा प्रकार हो सकते हैं, यह भी documented है: यदि एक्सप्रप्रस की सभी घटनाएं संख्यात्मक डेटा प्रकार या कोई गैर-संख्यात्मक डेटा प्रकार हैं जो स्पष्ट रूप से एक संख्यात्मक डेटा प्रकार में परिवर्तित हो सकती हैं, तो ओरेकल डेटाबेस उच्चतम संख्यात्मक प्राथमिकता के साथ तर्क निर्धारित करता है, अंतर्निहित शेष तर्कों को उस डेटा प्रकार में परिवर्तित करता है, और उस डेटा प्रकार को लौटाता है।। दरअसल यह आम अभिव्यक्ति के विपरीत भी है "कोलेसिस गैर-शून्य मूल्य की पहली घटना पर रुक जाता है", अन्यथा केस नंबर 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 के साथ डेटा प्रकार स्थिरता के लिए जांच करता है। पहले गैर-शून्य मान पर रोकना एक रनटाइम समस्या है, संकलन-समय समस्या नहीं। संकलन समय पर संकलक को पता नहीं है कि तीसरा मान (कहना) गैर-शून्य होगा; यह जोर देता है कि चौथा तर्क सही डेटा प्रकार का भी हो, भले ही उस चौथे मूल्य का वास्तव में मूल्यांकन नहीं किया जाएगा। – mathguy

1

एक और सबूत है कि संगठित() पहले गैर-शून्य मान के साथ मूल्यांकन नहीं रुकती:

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

इस भागो, तो जाँच my_sequence.currval;

संबंधित मुद्दे