NVL ve Coalesce arasındaki Oracle Farkları


208

Oracle'da NVL ve Coalesce arasında belirgin olmayan farklılıklar var mı?

Açık olan fark, birleşmenin parametre listesindeki ilk boş olmayan öğeyi döndürmesi, oysa nvl yalnızca iki parametre alır ve boş değilse ilkini döndürür, aksi takdirde ikinciyi döndürür.

Görünüşe göre NVL, birleşmenin sadece 'Temel Durum' versiyonu olabilir.

Bir şey mi kaçırıyorum?


Yanıtlar:


312

COALESCEANSI-92standardın bir parçası olan daha modern bir işlevdir .

NVLolduğunu Oracleo tanıtıldı, belirli 80herhangi standartlara önce s'.

İki değer olması durumunda eş anlamlılardır.

Ancak, farklı şekilde uygulanırlar.

NVLher zaman her iki argümanı da değerlendirirken, COALESCEgenellikle ilk olmayanı bulduğunda değerlendirmeyi durdurur NULL(sıra gibi bazı istisnalar vardır NEXTVAL):

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

Bu neredeyse için çalışır 0.5saniye oluşturduğu beri SYS_GUID()rağmen s' 1değil varlık NULL.

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

Bu 1, bunun a NULLolmadığını ve ikinci argümanı değerlendirmediğini anlar .

SYS_GUIDadlı kullanıcının oluşturulmaz ve sorgu anında yapılır.


11
Bunlar tam olarak eşanlamlı değildir ... En azından, verilen değerler farklı türdeyse NVL'nin örtülü bir veri türü dökümü yapması açısından bir fark bulabilirsiniz. Yani, örneğin, işlevi NVL olarak değiştirerek kaybolan iki NULL değeri (biri açıkça ayarlanmış ve diğeri veritabanındaki bir sütun, NUMBER türünde alınan) geçirerek COALESCE kullanarak bir hata alıyordum.
DanielM

170

NVL, ilk parametrenin veri türüne örtük bir dönüşüm gerçekleştirecektir, bu nedenle aşağıdakiler hata vermez

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

COALESCE tutarlı veri türleri bekliyor.

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

'tutarsız bir veri türü hatası' atacak


22

NVL ve COALESCE, sütunun NULL döndürmesi durumunda varsayılan değer sağlama işlevini gerçekleştirmek için kullanılır.

Farklar:

  1. NVL yalnızca 2 bağımsız değişkeni kabul ederken COALESCE birden çok bağımsız değişken alabilir
  2. NVL, boş olmayan bir değerin ilk oluşmasında hem bağımsız değişkenleri hem de COALESCE duraklarını değerlendirir.
  3. NVL, kendisine verilen ilk argümana dayanarak örtük bir veri türü dönüşümü yapar. COALESCE, tüm argümanların aynı veri tipinde olmasını bekliyor.
  4. COALESCE, UNION yan tümcelerini kullanan sorgularda sorunlar verir. Aşağıdaki örnek
  5. COALESCE, NVL Oracle'a özgü olduğu için ANSI standardıdır.

Üçüncü durum için örnekler. Diğer durumlar basit.

select nvl('abc',10) from dual; NVL, sayısal 10'un dizeye örtülü bir dönüşümünü gerçekleştireceği için çalışır.

select coalesce('abc',10) from dual; Hata - tutarsız veri türleriyle başarısız olur: beklenen CHAR NUMBER aldı

UNION kullanım örneği

SELECT COALESCE(a, sysdate) 
from (select null as a from dual 
      union 
      select null as a from dual
      );

ile başarısız 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
      ) ;

başarılı olur.

Daha fazla bilgi: http://www.plsqlinformation.com/2016/04/difference-between-nvl-and-coalesce-in-oracle.html


Ben "sendika" ile ilgili belirli bir sorun olduğunu sanmıyorum o kadar görünüyor Oracle varsayılan olarak bir char alt sorgu döküm null yazmak istiyor ve sonra aynı sorun madde 3 listelenen var (karışık veri tipleri). TO_DATE (NULL) olarak değiştirirseniz, hatayı almazsınız (kullandığım Oracle sürümünde hatayı yeniden oluşturamıyorum). Aksi takdirde cevabınızı kabul ediyorum. :-)
splashout

17

Plan işlemede de fark var.

Arama nvlsonucu dizine alınmış bir sütunla karşılaştırmayı içerdiğinde Oracle, şube filtrelerinin birleştirilmesiyle optimize edilmiş bir plan oluşturabilir .

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)

kaynaşabilecek:

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

Krediler http://www.xt-r.com/2012/03/nvl-coalesce-concatenation.html adresine gider .


6

Coalesce () yönteminin ilk null olmayan değerle değerlendirmeyi durdurmadığına dair bir başka kanıt:

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

Bunu çalıştır, sonra kontrol et my_sequence.currval;


5

Aslında her bir ifadeyi kabul edemiyorum.

"COALESCE tüm argümanların aynı veri tipinde olmasını bekliyor."

Bu yanlış, aşağıya bakın. Bağımsız değişkenler farklı veri türleri olabilir, bu da belgelenir : Tüm ifade örnekleri sayısal veri türü veya örtük olarak sayısal veri türüne dönüştürülebilen herhangi bir sayısal olmayan veri türüyse, Oracle Database üst üste en yüksek sayısal önceliğe sahip bağımsız değişkeni belirler kalan bağımsız değişkenleri bu veri türüne dönüştürür ve bu veri türünü döndürür. . Aslında bu, yaygın ifade ile "COALESCE Null olmayan bir değerin ilk oluşması durumunda durur" ifadesine aykırıdır, aksi takdirde test durumu No. 4 hata vermemelidir.

Ayrıca test durumu No. 5'e COALESCEgöre argümanların örtük bir dönüşümü vardır.

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
Yanıt: Test 4, "COALESCE, ilk sıfır olmayan değerde değerlendirmeyi durdurur" ile çelişir . Katılmıyorum. Test 4, derleyicinin COALESCE ile veri tipi tutarlılığını kontrol ettiğini gösterir. İlk null olmayan değerde durdurma, derleme zamanı sorunu değil bir çalışma zamanı sorunudur. Derleme zamanında derleyici üçüncü değerin (diyelim) boş olmayacağını bilmez; dördüncü argümanın da doğru veri türünde olduğu konusunda ısrar ediyor, dördüncü değer asla değerlendirilmese bile.
mathguy

3

Bu açık olsa da, bu soruyu soran Tom'un ortaya koyduğu bir şekilde bile bahsedildi. Ama tekrar başlayalım.

NVL'de yalnızca 2 bağımsız değişken olabilir. Birleşme 2'den fazla olabilir.

select nvl('','',1) from dual;// Sonuç:: ORA-00909geçersiz argüman sayısı
select coalesce('','','1') from dual; // Çıktı: 1 değerini döndürür


3

NVL: null değerini değiştirin.

COALESCE: İlk null olmayan ifadeyi ifade listesinden döndürür.

Tablo: PRICE_LIST

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

Aşağıda,

tüm ürünlere% 10 kar ekleyerek [1] Satış fiyatını belirleme örneği verilmiştir .
[2] Satın alma listesi fiyatı yoksa, satış fiyatı minimum fiyattır. Tasfiye satışı için.
[3] Minimum fiyat da yoksa, satış fiyatını varsayılan fiyat "50" olarak ayarlayın.

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

Gerçek hayattaki pratik örnekle açıklar.

+----------------+-----------+-----------------+----------------------+
| 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 ile kurallara ulaşabileceğimizi görebilirsiniz [1], [2]
Ancak COALSECE ile üç kurala da ulaşabiliriz.


hakkında ne diyorsun NVL(Purchase_Price + (Purchase_Price * 0.10), nvl(Min_Price,50)) . Veya hakkında: nvl(NVL(Purchase_Price + (Purchase_Price * 0.10), Min_Price) ,50) :)
Florin Ghita

hangisi daha hızlı, performans açısından ne kullanılmalı? yüklemek için binlerce kayıt düşünüyor musunuz?
rickyProgrammer
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.