Aynı masaya iki kez katılmanın en iyi yolu nedir?


108

Bu biraz karmaşık ama 2 masam var. Yapının şöyle bir şey olduğunu varsayalım:

*Table1*
ID
PhoneNumber1
PhoneNumber2

*Table2*
PhoneNumber
SomeOtherField

Tablolar, Table1.PhoneNumber1 -> Table2.PhoneNumber veya Table1.PhoneNumber2 -> Table2.PhoneNumber temelinde birleştirilebilir.

Şimdi, PhoneNumber1, SomeOtherField içeren PhoneNumber1, PhoneNumber2 ve PhoneNumber2'ye karşılık gelen SomeOtherField içeren bir sonuç kümesi almak istiyorum.

Bunu yapmanın 2 yolunu düşündüm - ya masaya iki kez katılarak ya da ON cümlesindeki OR ile bir kez katılarak.

Yöntem 1 :

SELECT t1.PhoneNumber1, t1.PhoneNumber2, 
   t2.SomeOtherFieldForPhone1, t3.someOtherFieldForPhone2
FROM Table1 t1
INNER JOIN Table2 t2
   ON t2.PhoneNumber = t1.PhoneNumber1
INNER JOIN Table2 t3
   ON t3.PhoneNumber = t1.PhoneNumber2

Bu işe yarıyor gibi görünüyor.

Yöntem 2 :

Bir şekilde buna benzeyen bir sorguya sahip olmak -

SELECT ...
FROM Table1
INNER JOIN Table2 
   ON Table1.PhoneNumber1 = Table2.PhoneNumber OR
      Table1.PhoneNumber2 = Table2.PhoneNumber

Bunu henüz çalıştırmadım ve bunu yapmanın bir yolu olup olmadığından emin değilim.

Bunu başarmanın en iyi yolu nedir? Her iki yol da basit ya da sezgisel görünmüyor ... Bunu yapmanın daha basit bir yolu var mı? Bu gereksinim genel olarak nasıl uygulanır?

Yanıtlar:


151

Öncelikle, telefon numaralarını doğal anahtar olarak kullanmaktan kurtulmak için bu tabloları yeniden düzenlemeye çalıştım. Ben doğal anahtarların hayranı değilim ve bu, bunun nedenine harika bir örnek. Doğal tuşlar, özellikle telefon numaraları gibi şeyler değişebilir ve sık sık. Bu değişiklik gerçekleştiğinde veritabanınızı güncellemek BÜYÜK, hataya açık bir baş ağrısı olacaktır. *

Yöntem 1 , tarif ettiğiniz gibi olsa da en iyi bahsinizdir. Adlandırma şeması ve kısa takma adlar nedeniyle biraz kısa görünüyor, ancak ... aynı masaya birden çok kez katılmak veya alt sorgular kullanmak söz konusu olduğunda takma ad sizin arkadaşınızdır.

Sadece işleri biraz temizlerdim:

SELECT t.PhoneNumber1, t.PhoneNumber2, 
   t1.SomeOtherFieldForPhone1, t2.someOtherFieldForPhone2
FROM Table1 t
JOIN Table2 t1 ON t1.PhoneNumber = t.PhoneNumber1
JOIN Table2 t2 ON t2.PhoneNumber = t.PhoneNumber2

Ben ne yaptım:

  • İÇİ belirtmenize gerek yok - SOL veya SAĞ'ı belirtmediğiniz gerçeği ima ediliyor
  • Birincil arama tablonuza n-sonek eklemeyin
  • N-Açıkça anlaşılması için birden çok kez kullanacağınız tablo takma adlarını ekleyin

* DBA'ların doğal anahtarları güncelleme sıkıntısını önlemesinin bir yolu, zayıf db tasarımıyla ilgili sorunları daha da artıran birincil anahtarları ve yabancı anahtar kısıtlamalarını belirtmemektir. Aslında bunu daha sık gördüm.


Bu çözümü sadece kendi sorunum için kullandım. Çok yardımcı oldu. Ancak, bunu görmeden önce, birbirine bağlanması gereken tabloları görebildiğim her yerde Birincil Anahtarları ve Yabancı Anahtarları uyguladım. Bu neden kötü bir fikir?
1

6
@volumeone - Cevabımın son kısmını yanlış anlamış olabilirsiniz. Birincil ve yabancı anahtarlar vardır iyi bir fikir. Bunlardan kaçınmak kötü bir uygulama, kötü tasarım ve düpedüz kötüdür.
Paul Sasik

Mükemmel .. ama bu durumda neden takma adlar bir zorunluluktur?
Raiden Core

Aynı masaya iki kez katılmadan bunu yapmanın bir yolu var mı? Belki nerede cümlesindeki bir koşulu kullanabilirsiniz ...
JohnOsborne

5

Birincisi, Phone1 veya (daha büyük olasılıkla) phone2 boş olmadığı sürece iyidir. Bu durumda iç birleştirme yerine Sol birleştirme kullanmak istersiniz.

İki telefon numarası alanı olan bir masanız olması genellikle kötü bir işarettir. Genellikle bu, veritabanı tasarımınızın hatalı olduğu anlamına gelir.


Harika nokta! Bu daha sonra başım ağrırdı ... teşekkürler!
froadie

4

UNIONİki birleşimi birleştirmek için kullanabilirsiniz :

SELECT Table1.PhoneNumber1 as PhoneNumber, Table2.SomeOtherField as OtherField
  FROM Table1
  JOIN Table2
    ON Table1.PhoneNumber1 = Table2.PhoneNumber
 UNION
SELECT Table1.PhoneNumber2 as PhoneNumber, Table2.SomeOtherField as OtherField
  FROM Table1
  JOIN Table2
    ON Table1.PhoneNumber2 = Table2.PhoneNumber

1
Bunu düşündüm, ama tek bir
normalden arındırılmış

Oh tamam, hemen hemen tam tersini varsaydım. Eğer durum buysa, ilk yönteminiz gibi bir şey kullanarak yaparım. Cevabımı düzenleyeceğim.
Pointy

3

Benim sorunum, hiç telefon numarası olmasa veya yalnızca bir telefon numarası (tam adres defteri) olsa bile kaydı görüntülemekti . Bu nedenle, sağda karşılık gelmese bile tüm kayıtları soldan alan bir LEFT JOIN kullandım. Benim için bu Microsoft Access SQL'de çalışıyor (parantez gerektiriyorlar!)

SELECT t.PhoneNumber1, t.PhoneNumber2, t.PhoneNumber3
   t1.SomeOtherFieldForPhone1, t2.someOtherFieldForPhone2, t3.someOtherFieldForPhone3
FROM 
(
 (
  Table1 AS t LEFT JOIN Table2 AS t3 ON t.PhoneNumber3 = t3.PhoneNumber
 )
 LEFT JOIN Table2 AS t2 ON t.PhoneNumber2 = t2.PhoneNumber
)
LEFT JOIN Table2 AS t1 ON t.PhoneNumber1 = t1.PhoneNumber;

2

İlk yöntem doğru yaklaşımdır ve ihtiyacınız olanı yapacaktır. Ancak, iç birleşimlerle, yalnızca içinde Table1her iki telefon numarası da mevcutsa satırları seçersiniz Table2. LEFT JOINTüm satırların Table1seçilmesi için bir yapmak isteyebilirsiniz . Telefon numaraları eşleşmezse, SomeOtherFields boş olacaktır. Eşleşen en az bir telefon numaranız olduğundan emin olmak istiyorsanız,WHERE t2.PhoneNumber IS NOT NULL OR t3.PhoneNumber IS NOT NULL

İkinci yöntemin bir sorunu olabilir: Table2hem PhoneNumber1ve hem de varsa ne olur PhoneNumber2? Hangi satır seçilecek? Verilerinize, yabancı anahtarlara, vb. Bağlı olarak bu bir sorun olabilir veya olmayabilir.

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.