Apa cara terbaik untuk bergabung di meja yang sama dua kali?


108

Ini agak rumit, tapi saya punya 2 tabel. Katakanlah strukturnya seperti ini:

*Table1*
ID
PhoneNumber1
PhoneNumber2

*Table2*
PhoneNumber
SomeOtherField

Tabel dapat digabungkan berdasarkan Table1.PhoneNumber1 -> Table2.PhoneNumber, atau Table1.PhoneNumber2 -> Table2.PhoneNumber.

Sekarang, saya ingin mendapatkan hasil yang berisi PhoneNumber1, SomeOtherField yang sesuai dengan PhoneNumber1, PhoneNumber2, dan SomeOtherField yang sesuai dengan PhoneNumber2.

Saya memikirkan 2 cara untuk melakukan ini - baik dengan bergabung di tabel dua kali, atau dengan bergabung sekali dengan OR di klausa ON.

Metode 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

Sepertinya ini berhasil.

Metode 2 :

Entah bagaimana memiliki kueri yang terlihat seperti ini -

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

Saya belum berhasil dan saya tidak yakin apakah ada cara untuk melakukannya.

Apa cara terbaik untuk melakukannya? Tidak ada cara yang tampak sederhana atau intuitif ... Adakah cara yang lebih mudah untuk melakukan ini? Bagaimana persyaratan ini diterapkan secara umum?

Jawaban:


151

Pertama, saya akan mencoba dan memfaktorkan ulang tabel ini agar tidak menggunakan nomor telepon sebagai kunci alami. Saya bukan penggemar kunci alami dan ini adalah contoh yang bagus mengapa. Tombol natural, terutama hal-hal seperti nomor telepon, dapat berubah dan sering kali berubah. Memperbarui basis data Anda ketika perubahan itu terjadi akan menjadi sakit kepala BESAR, rawan kesalahan. *

Metode 1 seperti yang Anda gambarkan, itu adalah taruhan terbaik Anda. Ini terlihat agak pendek karena skema penamaan dan alias pendek tetapi ... aliasing adalah teman Anda ketika harus bergabung dengan tabel yang sama beberapa kali atau menggunakan subkueri, dll.

Saya hanya akan membersihkan sedikit:

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

Apa yang saya lakukan:

  • Tidak perlu menentukan INNER - ini tersirat oleh fakta bahwa Anda tidak menentukan KIRI atau KANAN
  • Jangan n-sufiks tabel pencarian utama Anda
  • N-Suffix alias tabel yang akan Anda gunakan beberapa kali untuk membuatnya jelas

* Salah satu cara DBA menghindari sakit kepala saat memperbarui kunci alami adalah dengan tidak menentukan kunci utama dan batasan kunci asing yang selanjutnya menambah masalah dengan desain db yang buruk. Saya sebenarnya telah melihat ini lebih sering daripada tidak.


Saya baru saja menggunakan solusi ini untuk masalah saya sendiri. Itu sangat membantu. Namun, sebelum melihat ini saya menerapkan Kunci Utama dan Kunci Asing di mana pun saya dapat melihat tabel perlu bergabung satu sama lain. Mengapa ini ide yang buruk?
volume satu

6
@volumeone - Saya rasa Anda mungkin telah salah paham tentang bagian terakhir jawaban saya. Kunci utama dan kunci asing adalah ide yang bagus. Menghindarinya adalah praktik yang buruk, desain yang buruk, dan buruk.
Paul Sasik

Sempurna..tapi mengapa alias harus dalam situasi ini?
Raiden Core

Apakah ada cara untuk melakukan ini tanpa menggabungkan tabel yang sama dua kali? Mungkin menggunakan kondisi di mana klausa ...
JohnOsborne

5

Yang pertama bagus kecuali jika Phone1 atau (lebih mungkin) phone2 bisa nihil. Dalam hal ini Anda ingin menggunakan gabungan Kiri dan bukan gabungan dalam.

Biasanya pertanda buruk ketika Anda memiliki meja dengan dua bidang nomor telepon. Biasanya ini berarti desain database Anda cacat.


Poin yang bagus! Ini akan membuatku pusing sekali nanti ... terima kasih!
froadie

4

Anda bisa menggunakan UNIONuntuk menggabungkan dua gabungan:

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
Saya memikirkan ini, tetapi saya ingin itu dikembalikan sebagai satu catatan yang
dinormalisasi

Oh oke, saya berasumsi sebaliknya. Jika itu masalahnya maka saya akan melakukannya dengan menggunakan sesuatu seperti metode pertama Anda. Saya akan mengedit jawaban saya.
Pointy

3

Masalah saya adalah menampilkan catatan meskipun tidak ada atau hanya ada satu nomor telepon (buku alamat lengkap). Oleh karena itu saya menggunakan LEFT JOIN yang mengambil semua record dari kiri, meskipun tidak ada yang sesuai di sebelah kanan. Bagi saya ini berfungsi di Microsoft Access SQL (mereka memerlukan tanda kurung!)

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

Metode pertama adalah pendekatan yang tepat dan akan melakukan apa yang Anda butuhkan. Namun, dengan gabungan dalam, Anda hanya akan memilih baris dari Table1jika kedua nomor telepon ada Table2. Anda mungkin ingin melakukan LEFT JOINagar semua baris dari Table1dipilih. Jika nomor telepon tidak cocok, maka SomeOtherFields akan menjadi nol. Jika Anda ingin memastikan Anda memiliki setidaknya satu nomor telepon yang cocok, Anda dapat melakukannyaWHERE t2.PhoneNumber IS NOT NULL OR t3.PhoneNumber IS NOT NULL

Metode kedua mungkin bermasalah: apa yang terjadi jika Table2memiliki keduanya PhoneNumber1dan PhoneNumber2? Baris mana yang akan dipilih? Tergantung pada data Anda, kunci asing, dll. Ini mungkin menjadi masalah atau tidak.

Dengan menggunakan situs kami, Anda mengakui telah membaca dan memahami Kebijakan Cookie dan Kebijakan Privasi kami.
Licensed under cc by-sa 3.0 with attribution required.