Birleştirmelerde null değerleri neden kullanamıyorum?


13

Sorgu sorununu kullanarak çözdüm ... row_number() over (partition by... neden birleştirmelerde null değerleri olan sütunları kullanamadığımıza dair daha genel bir soru. Bir null için bir null değeri null değerine eşit olamaz?

Yanıtlar:


31

Bir null için bir null değeri null değerine eşit olamaz?

Oracle'a bunu yapmasını söyleyin:

select *
from one t1 
  join two t2 on coalesce(t1.id, -1) = coalesce(t2.id, -1);

(Standart SQL'de t1.id is not distinct from t2.idsıfır güvenlikli bir eşitlik operatörü almak için kullanabileceğinizi , ancak Oracle'ın bunu desteklemediğini unutmayın)

Ancak bu yalnızca değiştirme değeri (yukarıdaki örnekte -1) tabloda görünmüyorsa işe yarar. Sayılar için böyle bir "sihirli" değer bulmak mümkün olabilir , ancak karakter değerleri için çok zor olacaktır (özellikle Oracle da boş bir dizgiyi tedavi ettiği için null)

Artı: hiçbir dizin idsütunları kullanılacaktır (eğer olabilir bir fonksiyon bazlı endeks tanımlamak coalesce()ifade rağmen).

Sihirli değerler olmadan tüm türler için çalışan başka bir seçenek:

              on t1.id = t2.id or (t1.id is null and t2.id is null)

Ama asıl soru şu: bu mantıklı mı?

Aşağıdaki örnek verileri göz önünde bulundurun:

Birinci masa

id
----
1
2
(null)
(null)

Tablo iki

id
----
1
2
(null)
(null)
(null)

Birleştirmede hangi null değerlerin birleşimi seçilmelidir? Yukarıdaki örneğim, tüm boş değerler için çapraz birleştirme gibi bir şeyle sonuçlanacaktır.

T1_ID  | T2_ID 
-------+-------
     1 |      1
     2 |      2
(null) | (null)
(null) | (null)
(null) | (null)
(null) | (null)
(null) | (null)
(null) | (null)

6

Alternatif INTERSECTolarak, eşitlik operatörü olarak kullanarak iki null değerinin birbiriyle eşleşmesini sağlayabilirsiniz :

SELECT
  *
FROM
  t1
  INNER JOIN t2
    ON EXISTS (SELECT t1.ID FROM DUAL INTERSECT SELECT t2.ID FROM DUAL)
;

Bir örnek için bu DBFiddle demosuna bakın .

Tabii ki, bu oldukça ağız dolusu görünüyor, ancak aslında BriteSponge'un önerisinden çok daha uzun değil . Ancak, eğer cezai affederseniz, daha önce bahsedilenlerin standart olarak, yani IS NOT DISTINCT FROMoperatör olan, henüz Oracle'da desteklenmeyen kısa özlüğe uyması kesinlikle bir eşleşme değildir.


2

Tam olarak söylemek gerekirse, fonksiyonun SYS_OP_MAP_NONNULLartık 12c belgelerinde belgelendiği gibi boş değerleri karşılaştırmak için güvenle kullanılabileceğinden bahsedeceğim . Bu, Oracle'ın rasgele kaldırıp kodunuzu kırmayacağı anlamına gelir.

SELECT *
FROM   one t1 
       JOIN two t2
         ON SYS_OP_MAP_NONNULL(t1.id) = SYS_OP_MAP_NONNULL(t2.id)

Avantajı 'sihirli' sayı problemiyle karşılaşmamanızdır.

Oracle belgelerindeki referans Temel Materyalleştirilmiş Görünümler - Materyalleştirilmiş Görünümler için Dizin Seçme konusudur .


Şimdi belgeleniyor mu? Çünkü AskTom (2003'te) şunları söyledi: " - belgelenmemiş ve bu nedenle, insanların sadece" okumayı durdur "durmasını sağlayacak bir işlevselliği değiştirme veya değiştirme riskiwhere (a = b or (a is null and b is null))sys_op_map_nonnull
ypercubeᵀᴹ

Bağlantınız varsa, lütfen soruya ekleyin. 12c İşlevlerinde bahsetmedim, ancak Oracle belgelerini ve belirli sürümünü aramak oldukça zor.
ypercubeᵀᴹ

2

Kod çözme kullanarak null değerleri birleştirebilirsiniz:

on decode(t1.id, t2.id, 1, 0) = 1

decodenull değerlerine eşit davranır, dolayısıyla bu "sihirli" sayılar olmadan çalışır. İki sütun aynı veri türüne sahip olmalıdır.

En okunabilir kodu yapmayacak, ancak muhtemelen t1.id = t2.id or (t1.id is null and t2.id is null)


1

Birleştirmelerde null değerleri neden kullanamıyorsunuz? Oracle'da aşağıdakilerin ikisi de doğru olarak değerlendirilmez:

  • NULL = NULL
  • NULL <> NULL

Elimizdeki bu yüzden IS NULL/ IS NOT NULLnull değerleri denetlemek için.
Bunu test etmek için şunları yapabilirsiniz:

SELECT * FROM table_name WHERE NULL = NULL

Birleşmeler bir boole koşulunu değerlendiriyor ve bunları farklı şekilde çalışacak şekilde programlamıyorlardı. Birleştirme koşuluna birden çok işaret koyabilir ve başka koşullar ekleyebilirsiniz; sadece bir boole ifadesi olarak değerlendirir.

Sanırım bir sıfır, tutarlılık uğruna birleştirme içindeki sıfırdan eşit olamaz. Karşılaştırma operatörünün olağan davranışına meydan okuyacaktır.


NULL = anythingsonuçları NULLSQL standardı öyle diyor çünkü. Bir satır birleştirme koşulunu yalnızca ifade doğruysa karşılar.
Laurenz Albe

1
Gerçek uygulama ayrıntısının ötesinde (her zaman böyle değildir: bazı DB'ler NULL ile NULL arasında bazı / tüm amaçlar için eşitleme seçeneğine sahiptir) mantıklı bir neden vardır: NULL bilinmiyor. NULL ile NULL karşılaştırdığınızda, "makul olmayan bu şey bu bilinmeyen şeye eşittir" diye soruyorsunuz, tek makul cevap "bilinmeyen" - başka bir NULL (karşılaştırma durumunda false ile eşleştirilir).
David Spillett

-4

İlişkisel veritabanlarının çoğunda null değeri bilinmeyen olarak kabul edilir. Tüm HEX sıfırları ile karıştırılmamalıdır. bir şey null (bilinmiyor) içeriyorsa, onu karşılaştıramazsınız.

Unknown = Known False
Unknown = Unknown False
Unknown >= Known False
Known >= Unknown False

Bu, boole ifadesinde bir işlenen olarak null değeriniz olduğunda, diğer bölüm her zaman doğru olacaktır.

Geliştiriciler tarafından null'a karşı genel nefretin aksine, null'un yeri vardır. Bilinmeyen bir şey varsa null kullanın.


6
Aslında verdiğiniz tüm örnek karşılaştırmalar, verim UNKNOWNdeğil FALSE;)
ypercubeᵀᴹ

Haklısınız, ancak bir boole ifadesinin amacı yalnızca doğru veya yanlış sonuç vermektir, bu yüzden burada delirmeyelim :).
jujiro
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.