Cách tốt nhất để tham gia vào cùng một bàn hai lần là gì?


108

Điều này hơi phức tạp, nhưng tôi có 2 bảng. Giả sử cấu trúc như thế này:

*Table1*
ID
PhoneNumber1
PhoneNumber2

*Table2*
PhoneNumber
SomeOtherField

Các bảng có thể được nối dựa trên Table1.PhoneNumber1 -> Table2.PhoneNumber hoặc Table1.PhoneNumber2 -> Table2.PhoneNumber.

Bây giờ, tôi muốn nhận tập kết quả chứa PhoneNumber1, SomeOtherField tương ứng với PhoneNumber1, PhoneNumber2 và SomeOtherField tương ứng với PhoneNumber2.

Tôi đã nghĩ ra 2 cách để làm điều này - bằng cách tham gia vào bảng hai lần hoặc bằng cách tham gia một lần với OR trong mệnh đề BẬT.

Phương pháp 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

Điều này có vẻ hiệu quả.

Phương pháp 2 :

Để bằng cách nào đó có một truy vấn trông giống như thế này -

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

Tôi vẫn chưa làm được điều này và tôi không chắc liệu có cách nào để thực hiện nó hay không.

Cách tốt nhất để thực hiện điều này là gì? Không có cách nào có vẻ đơn giản hoặc trực quan ... Có cách nào đơn giản hơn để làm điều này không? Yêu cầu này thường được thực hiện như thế nào?

Câu trả lời:


151

Đầu tiên, tôi sẽ thử và cấu trúc lại các bảng này để tránh sử dụng số điện thoại làm khóa tự nhiên. Tôi không phải là một fan hâm mộ của các phím tự nhiên và đây là một ví dụ tuyệt vời tại sao. Các phím tự nhiên, đặc biệt là những thứ như số điện thoại, có thể thay đổi và thường xuyên như vậy. Việc cập nhật cơ sở dữ liệu của bạn khi thay đổi đó xảy ra sẽ là một vấn đề LỚN, dễ xảy ra lỗi. *

Mặc dù vậy, phương pháp 1 như bạn mô tả là cách tốt nhất của bạn. Có vẻ hơi ngắn do cách đặt tên và bí danh ngắn nhưng ... bí danh là bạn của bạn khi tham gia cùng một bảng nhiều lần hoặc sử dụng truy vấn con, v.v.

Tôi chỉ dọn dẹp mọi thứ một chút:

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

Tôi đã làm gì:

  • Không cần chỉ định INNER - ngụ ý rằng bạn không chỉ định LEFT hoặc RIGHT
  • Không có hậu tố n trong bảng tra cứu chính của bạn
  • N-Thêm các bí danh bảng mà bạn sẽ sử dụng nhiều lần để làm cho nó rõ ràng

* Một cách các DBA tránh được những vấn đề đau đầu khi cập nhật khóa tự nhiên là không chỉ định khóa chính và các ràng buộc khóa ngoại, điều này càng làm tăng thêm các vấn đề với thiết kế db kém. Tôi thực sự đã thấy điều này thường xuyên hơn không.


Tôi vừa mới sử dụng giải pháp này cho vấn đề của riêng mình. Nó đã giúp rất nhiều. Tuy nhiên, trước khi thấy điều này, tôi đã áp dụng Phím Chính và Phím Ngoại ở bất cứ đâu tôi có thể thấy các bảng cần liên kết với nhau. Tại sao đây là một ý tưởng tồi?
tập một

6
@volumeone - Tôi nghĩ rằng bạn có thể đã hiểu sai phần cuối cùng trong câu trả lời của tôi. Khóa chính và khóa ngoài một ý kiến ​​hay. Tránh chúng là thực hành kém, thiết kế xấu và đơn giản là xấu.
Paul Sasik

Hoàn hảo..nhưng tại sao bí danh là bắt buộc trong tình huống này?
Raiden Core,

Có cách nào để làm điều này mà không cần tham gia cùng một bảng hai lần không? Có thể sử dụng một điều kiện trong mệnh đề where ...
JohnOsborne

5

Đầu tiên là tốt trừ khi Phone1 hoặc (nhiều khả năng) phone2 có thể là rỗng. Trong trường hợp đó, bạn muốn sử dụng liên kết Trái thay vì liên kết bên trong.

Nó thường là một dấu hiệu xấu khi bạn có một bảng có hai trường số điện thoại. Thông thường, điều này có nghĩa là thiết kế cơ sở dữ liệu của bạn có sai sót.


Điểm tuyệt vời! Điều này sẽ khiến tôi đau đầu sau này ... cảm ơn!
froadie

4

Bạn có thể sử dụng UNIONđể kết hợp hai phép nối:

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
Tôi nghĩ về điều này, nhưng tôi cần nó để được trả lại như một kỷ lục denormalized đơn ...
froadie

Ồ được rồi, tôi cho rằng điều ngược lại hoàn toàn. Nếu đó là trường hợp thì tôi sẽ làm điều đó bằng cách sử dụng một cái gì đó giống như phương pháp đầu tiên của bạn. Tôi sẽ chỉnh sửa câu trả lời của mình.
Pointy

3

Vấn đề của tôi là hiển thị hồ sơ ngay cả khi không có hoặc chỉ tồn tại một số điện thoại (sổ địa chỉ đầy đủ). Do đó, tôi đã sử dụng LEFT JOIN lấy tất cả các bản ghi từ bên trái, ngay cả khi không có bản ghi nào tương ứng ở bên phải. Đối với tôi, điều này hoạt động trong Microsoft Access SQL (chúng yêu cầu dấu ngoặc đơn!)

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

Phương pháp đầu tiên là cách tiếp cận phù hợp và sẽ làm được những gì bạn cần. Tuy nhiên, với các phép nối bên trong, bạn sẽ chỉ chọn các hàng Table1nếu cả hai số điện thoại đều tồn tại Table2. Bạn có thể muốn thực hiện LEFT JOINđể tất cả các hàng từ Table1được chọn. Nếu số điện thoại không khớp, thì SomeOtherFields sẽ là null. Nếu bạn muốn đảm bảo rằng bạn có ít nhất một số điện thoại phù hợp thì bạn có thể làmWHERE t2.PhoneNumber IS NOT NULL OR t3.PhoneNumber IS NOT NULL

Phương pháp thứ hai có thể có một vấn đề: điều gì xảy ra nếu Table2có cả hai PhoneNumber1PhoneNumber2? Hàng nào sẽ được chọn? Tùy thuộc vào dữ liệu của bạn, khóa ngoại, v.v., điều này có thể là một vấn đề.

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.