CẢNH BÁO VỀ GIẢI PHÁP:
NHIỀU GIẢI PHÁP HIỆN HỮU SIVE GỬI ĐẦU RA SAU NẾU ROWS KHÔNG ĐỘC ĐÁO
Nếu bạn là người duy nhất tạo bảng, điều này có thể không liên quan, nhưng một số giải pháp sẽ cung cấp một số hàng đầu ra khác với mã được đề cập, khi một trong các bảng có thể không chứa các hàng duy nhất.
CẢNH BÁO VỀ TUYÊN BỐ VẤN ĐỀ:
Ở VỚI NHIỀU MÀU SẮC KHÔNG HIỆN TẠI, HÃY CẨN THẬN NHỮNG GÌ BẠN MUỐN
Khi tôi thấy một cột có hai cột, tôi có thể tưởng tượng nó có nghĩa là hai điều:
- Giá trị của cột a và cột b xuất hiện độc lập trong bảng khác
- Các giá trị của cột a và cột b xuất hiện trong bảng khác trên cùng một hàng
Kịch bản 1 khá tầm thường, chỉ cần sử dụng hai câu lệnh IN.
Theo hầu hết các câu trả lời hiện có, tôi xin cung cấp tổng quan về các phương pháp tiếp cận được đề cập và bổ sung cho Kịch bản 2 (và phán đoán ngắn gọn):
EXISTS (An toàn, được khuyến nghị cho SQL Server)
Như được cung cấp bởi @mrdenny, EXISTS nghe chính xác như những gì bạn đang tìm kiếm, đây là ví dụ của anh ấy:
SELECT * FROM T1
WHERE EXISTS
(SELECT * FROM T2
WHERE T1.a=T2.a and T1.b=T2.b)
LEFT SEMI THAM GIA (An toàn, được khuyến nghị cho các phương ngữ hỗ trợ nó)
Đây là một cách rất ngắn gọn để tham gia, nhưng thật không may, hầu hết các phương ngữ SQL, bao gồm cả máy chủ SQL hiện không hỗ trợ nó.
SELECT * FROM T1
LEFT SEMI JOIN T2 ON T1.a=T2.a and T1.b=T2.b
Nhiều câu lệnh IN (An toàn, nhưng hãy cẩn thận khi sao chép mã)
Như @cataclysm đã đề cập bằng cách sử dụng hai câu lệnh IN cũng có thể thực hiện thủ thuật này, có lẽ nó thậm chí sẽ vượt trội hơn các giải pháp khác. Tuy nhiên, điều bạn nên hết sức cẩn thận là sao chép mã. Nếu bạn muốn chọn từ một bảng khác hoặc thay đổi câu lệnh where, thì nguy cơ tăng cao là bạn tạo ra sự không nhất quán trong logic của mình.
Giải pháp cơ bản
SELECT * from T1
WHERE a IN (SELECT a FROM T2 WHERE something)
AND b IN (SELECT b FROM T2 WHERE something)
Giải pháp không trùng lặp mã (Tôi tin rằng điều này không hoạt động trong các truy vấn SQL Server thông thường)
WITH mytmp AS (SELECT a, b FROM T2 WHERE something);
SELECT * from T1
WHERE a IN (SELECT a FROM mytmp)
AND b IN (SELECT b FROM mytmp)
INNER THAM GIA (về mặt kỹ thuật có thể được thực hiện an toàn, nhưng thường thì điều này không được thực hiện)
Lý do tại sao tôi không khuyên bạn nên sử dụng phép nối bên trong làm bộ lọc, bởi vì trong thực tế, mọi người thường để các bản sao ở bảng bên phải gây ra các bản sao ở bảng bên trái. Và sau đó để làm cho vấn đề tồi tệ hơn, đôi khi họ làm cho kết quả cuối cùng khác biệt trong khi bảng bên trái thực sự không cần phải là duy nhất (hoặc không phải là duy nhất trong các cột bạn chọn). Hơn nữa, nó cung cấp cho bạn cơ hội để thực sự chọn một cột không tồn tại trong bảng bên trái.
SELECT T1.* FROM T1
INNER JOIN
(SELECT DISTINCT a, b FROM T2) AS T2sub
ON T1.a=T2sub.a AND T1.b=T2sub.b
Những lỗi phổ biến nhất:
- Tham gia trực tiếp trên T2, không có truy vấn con an toàn. Kết quả là có nguy cơ trùng lặp)
- CHỌN * (Được sắp xếp để lấy các cột từ T2)
- CHỌN c (Không đảm bảo rằng cột của bạn đến và luôn luôn đến từ T1)
- Không có DISTINCT hoặc DISTINCT ở sai vị trí
CONCATENATION CỦA COLUMNS VỚI SEPARATOR (Không an toàn lắm, hiệu suất khủng khiếp)
Vấn đề chức năng là nếu bạn sử dụng một dấu phân tách có thể xảy ra trong một cột, sẽ rất khó để đảm bảo rằng kết quả chính xác 100%. Vấn đề kỹ thuật là phương pháp này thường phát sinh chuyển đổi loại và hoàn toàn bỏ qua các chỉ mục, dẫn đến hiệu suất có thể khủng khiếp. Mặc dù có những vấn đề này, tôi phải thừa nhận rằng đôi khi tôi vẫn sử dụng nó cho các truy vấn đặc biệt trên các bộ dữ liệu nhỏ.
SELECT * FROM T1
WHERE CONCAT(a,"_",b) IN
(SELECT CONCAT(a,"_",b) FROM T2)
Lưu ý rằng nếu các cột của bạn là số, một số phương ngữ SQL sẽ yêu cầu bạn chuyển chúng thành chuỗi trước. Tôi tin rằng máy chủ SQL sẽ làm điều này tự động.
Để kết thúc mọi thứ: Như thường lệ, có nhiều cách để thực hiện điều này trong SQL, sử dụng các lựa chọn an toàn sẽ tránh được các bất ngờ và giúp bạn tiết kiệm thời gian và tiêu đề trong thời gian dài.