ПОПЕРЕДЖЕННЯ ПРО РІШЕННЯ:
МНОГО ІСНУЮЧІ РІШЕННЯ ДАВАТИСЬ НЕВЕРСІЙНИЙ ВІДКЛЮЧЕННЯ, ЯКЩО РУДИ НЕ БУДУТЬ Унікальними
Якщо ви є єдиною особою, яка створює таблиці, це може не бути актуальним, але декілька рішень дадуть різну кількість вихідних рядків від відповідного коду, коли одна з таблиць може не містити унікальних рядків.
ПОПЕРЕДЖЕННЯ ПРО ЗАЯВКУ ПРОБЛЕМИ:
В МНОГО СТРУМКАХ НЕ ІСНУЄТЬСЯ, ДУМАЙТЕ ДЕРЖАВНО, ЧОГО Ви хочете
Коли я бачу вкладку з двома стовпцями, я можу уявити, що це означає дві речі:
- Значення стовпця a та стовпця b відображаються в іншій таблиці незалежно
- Значення стовпця a та стовпця b відображаються в іншій таблиці разом у тому ж рядку
Сценарій 1 досить тривіальний, просто використовуйте два оператори IN.
Відповідно до більшості існуючих відповідей, я надаю огляд згаданих та додаткових підходів до сценарію 2 (і коротке судження):
ДОДАТИ (Безпечно, рекомендується для SQL Server)
Як надає @mrdenny, EXISTS звучить саме так, як ви шукаєте, ось його приклад:
SELECT * FROM T1
WHERE EXISTS
(SELECT * FROM T2
WHERE T1.a=T2.a and T1.b=T2.b)
ЛЕВИЙ SEMI ПРИЄДНАЙТЕСЬ (Безпечний, рекомендується для діалектів, які його підтримують)
Це дуже стислий спосіб приєднатися, але, на жаль, більшість діалектів SQL, включаючи SQL-сервер, наразі не підтримують його.
SELECT * FROM T1
LEFT SEMI JOIN T2 ON T1.a=T2.a and T1.b=T2.b
Кілька заяв IN (Безпечно, але остерігайтеся дублювання коду)
Як зазначає @cataclysm, використання двох висловлювань IN може також зробити трюк, можливо, це навіть випереджає інші рішення. Однак, вам слід бути дуже обережним - це дублювання коду. Якщо ви хочете колись вибрати з іншої таблиці або змінити оператор where, це збільшує ризик створення невідповідностей у вашій логіці.
Основне рішення
SELECT * from T1
WHERE a IN (SELECT a FROM T2 WHERE something)
AND b IN (SELECT b FROM T2 WHERE something)
Рішення без дублювання коду (я вважаю, що це не працює в звичайних запитах SQL Server)
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)
ВНУТРІШНЯ ПРИЄДНАЙТЕСЬ (технічно це можна зробити безпечним, але часто це не робиться)
Причина, чому я не рекомендую використовувати внутрішнє з'єднання як фільтр, полягає в тому, що на практиці люди часто дають дублікати в правій таблиці викликати дублікати в лівій таблиці. А потім, щоб погіршити ситуацію, іноді вони роблять кінцевий результат виразним, хоча ліва таблиця насправді не повинна бути унікальною (або не унікальною у вибраних стовпцях). Крім того, це дає можливість фактично вибрати стовпчик, який не існує в лівій таблиці.
SELECT T1.* FROM T1
INNER JOIN
(SELECT DISTINCT a, b FROM T2) AS T2sub
ON T1.a=T2sub.a AND T1.b=T2sub.b
Найпоширеніші помилки:
- Приєднання безпосередньо на T2, без безпечного підпиту. Результат ризику дублювання)
- SELECT * (гарантовано для отримання стовпців з T2)
- SELECT c (не гарантує, що ваш стовпець надходить і завжди буде надходити з T1)
- Немає DISTINCT або DISTINCT у неправильному місці
СУЧАСНЯ КОЛІН З СЕПАРАТОРОМ (не дуже безпечне, жахливе виконання)
Функціональна проблема полягає в тому, що якщо ви використовуєте роздільник, який може виникнути у стовпчику, він стає непростим, щоб результат був 100% точним. Технічна проблема полягає в тому, що цей метод часто здійснює перетворення типів і повністю ігнорує індекси, що призводить до можливо жахливої продуктивності. Незважаючи на ці проблеми, я маю визнати, що іноді я все-таки використовую його для спеціальних запитів на невеликих наборах даних.
SELECT * FROM T1
WHERE CONCAT(a,"_",b) IN
(SELECT CONCAT(a,"_",b) FROM T2)
Зауважте, що якщо ваші стовпці мають числовий характер, для деяких діалектів SQL потрібно буде спочатку надати їх рядкам. Я вірю, що SQL-сервер зробить це автоматично.
Для завершення речей: Як зазвичай, існує багато способів зробити це в SQL, використання безпечного вибору дозволить уникнути несподіванок та заощадить ваш час та головні болі в довгостроковій перспективі.