SQL WHERE .. IN предложение несколько столбцов - PullRequest
151 голосов
/ 16 июля 2009

Мне нужно реализовать следующий запрос в SQL Server:

select *
from table1
WHERE  (CM_PLAN_ID,Individual_ID)
IN
(
 Select CM_PLAN_ID, Individual_ID
 From CRM_VCM_CURRENT_LEAD_STATUS
 Where Lead_Key = :_Lead_Key
)

Но предложение WHERE..IN допускает только 1 столбец. Как я могу сравнить 2 или более столбцов с другим внутренним SELECT?

Ответы [ 13 ]

114 голосов
/ 16 июля 2009

Вместо этого вы захотите использовать синтаксис WHERE EXISTS.

SELECT *
FROM table1
WHERE EXISTS (SELECT *
              FROM table2
              WHERE Lead_Key = @Lead_Key
                        AND table1.CM_PLAN_ID = table2.CM_PLAN_ID
                        AND table1.Individual_ID = table2.Individual_ID)
101 голосов
/ 16 июля 2009

Вы можете создать производную таблицу из подзапроса и присоединить table1 к этой производной таблице:

select * from table1 LEFT JOIN 
(
   Select CM_PLAN_ID, Individual_ID
   From CRM_VCM_CURRENT_LEAD_STATUS
   Where Lead_Key = :_Lead_Key
) table2
ON 
   table1.CM_PLAN_ID=table2.CM_PLAN_ID
   AND table1.Individual=table2.Individual
WHERE table2.CM_PLAN_ID IS NOT NULL
12 голосов
/ 16 июля 2009

Простое предложение EXISTS самое чистое

select *
from table1 t1
WHERE
EXISTS
(
 Select * --or 1. No difference.
 From CRM_VCM_CURRENT_LEAD_STATUS Ex
 Where Lead_Key = :_Lead_Key
-- correlation here
AND
t1.CM_PLAN_ID = Ex.CM_PLAN_ID AND t1.CM_PLAN_ID =  Ex.Individual_ID
)

Если у вас есть несколько строк в корреляции, то JOIN дает несколько строк в выводе, так что вам нужно различить. Что обычно делает EXISTS более эффективным.

Примечание. "SELECT" * с JOIN также включает столбцы из таблиц ограничения строк

7 голосов
/ 09 декабря 2015
select * from tab1 where (col1,col2) in (select col1,col2 from tab2)

Примечание:
Oracle игнорирует строки, в которых один или несколько выбранных столбцов имеют значение NULL. В этих случаях вы, вероятно, захотите использовать функцию NVL , чтобы отобразить NULL в специальное значение (которое не должно быть в значениях);

select * from tab1
where (col1, NVL(col2, '---') in (select col1, NVL(col2, '---') from tab2)
4 голосов
/ 27 января 2019

ПРЕДУПРЕЖДЕНИЕ О РЕШЕНИЯХ:

МНОГИЕ СУЩЕСТВУЮЩИЕ РЕШЕНИЯ ДАЮТ НЕПРАВИЛЬНЫЙ ВЫХОД, ЕСЛИ СТРОКИ НЕ УНИКАЛЬНЫ *

Если вы являетесь единственным человеком, создающим таблицы, это может быть неактуально, но несколько решений приведут к разному количеству выходных строк из рассматриваемого кода, когда одна из таблиц может не содержать уникальных строк.

ПРЕДУПРЕЖДЕНИЕ О ЗАЯВЛЕНИИ ЗАДАЧИ:

В С НЕСКОЛЬКИМИ КОЛОННАМИ НЕ СУЩЕСТВУЕТ, ВНИМАТЕЛЬНО ДУМАЙТЕ, ЧТО ВЫ ХОТИТЕ

Когда я вижу вход с двумя столбцами, я могу представить, что он означает две вещи:

  1. Значения столбца a и столбца b отображаются в другой таблице независимо
  2. Значения столбца a и столбца b появляются в другой таблице вместе в одной строке

Сценарий 1 довольно тривиален, просто используйте два оператора IN.

В соответствии с большинством существующих ответов, я настоящим предоставляю обзор упомянутых и дополнительных подходов к Сценарию 2 (и краткое суждение):

EXISTS (Безопасный, рекомендуется для SQL Server)

Как сказано в @mrdenny, EXISTS звучит именно так, как вы ищете, вот его пример:

SELECT * FROM T1
WHERE EXISTS
(SELECT * FROM T2 
 WHERE T1.a=T2.a and T1.b=T2.b)

LEFT SEMI JOIN (Безопасно, рекомендуется для диалектов, которые его поддерживают)

Это очень краткий способ присоединения, но, к сожалению, большинство диалектов 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)

INNER JOIN (технически это можно сделать безопасным, но часто этого не делается)

Причина, по которой я не рекомендую использовать внутреннее объединение в качестве фильтра, заключается в том, что на практике люди часто допускают дубликаты в правой таблице, вызывая дубликаты в левой таблице. И что еще хуже, они иногда делают конечный результат отличным, в то время как левая таблица может фактически не быть уникальной (или не уникальной в выбранных вами столбцах). Кроме того, это дает вам возможность фактически выбрать столбец, который не существует в левой таблице.

SELECT T1.* FROM T1
INNER JOIN 
(SELECT DISTINCT a, b FROM T2) AS T2sub
ON T1.a=T2sub.a AND T1.b=T2sub.b

Наиболее распространенные ошибки:

  1. Присоединение непосредственно к T2, без безопасного подзапроса. В результате возникает риск дублирования)
  2. SELECT * (гарантированно получить столбцы из T2)
  3. SELECT c (не гарантирует, что ваш столбец будет приходить и всегда будет поступать с T1)
  4. Нет DISTINCT или DISTINCT в неправильном месте

СЦЕПЛЕНИЕ КОЛОНН С СЕПАРАТОРОМ (Не очень безопасно, ужасная производительность)

Функциональная проблема заключается в том, что если вы используете разделитель, который может находиться в столбце, будет сложно убедиться, что результат на 100% точен. Техническая проблема заключается в том, что этот метод часто выполняет преобразования типов и полностью игнорирует индексы, что может привести к ужасной производительности. Несмотря на эти проблемы, я должен признать, что иногда я все еще использую его для специальных запросов в небольших наборах данных.

SELECT * FROM T1
WHERE CONCAT(a,"_",b) IN 
(SELECT CONCAT(a,"_",b) FROM T2)

Обратите внимание, что если ваши столбцы являются числовыми, некоторые диалекты SQL требуют, чтобы вы сначала приводили их к строкам. Я верю, что SQL-сервер сделает это автоматически.


Подводя итог: как обычно, есть много способов сделать это в SQL, использование безопасного выбора позволит избежать неожиданностей и сэкономить ваше время и трудности в долгосрочной перспективе.

2 голосов
/ 16 июля 2009

Зачем использовать ГДЕ СУЩЕСТВУЮЩИЕ или ПРОИЗВОДНЫЕ ТАБЛИЦЫ, когда вы можете просто выполнить обычное внутреннее соединение:

SELECT t.*
FROM table1 t
INNER JOIN CRM_VCM_CURRENT_LEAD_STATUS s
    ON t.CM_PLAN_ID = s.CM_PLAN_ID
    AND t.Individual_ID = s.Individual_ID
WHERE s.Lead_Key = :_Lead_Key

Если пара (CM_PLAN_ID, Individual_ID) не уникальна в таблице состояний, вам может потребоваться вместо этого SELECT DISTINCT t. *.

0 голосов
/ 07 сентября 2018
Postgres SQL  : version 9.6
Total records on tables : mjr_agent = 145, mjr_transaction_item = 91800

1.Использование с EXISTS [Среднее время запроса: 1,42 с]

SELECT count(txi.id) 
FROM 
mjr_transaction_item txi
WHERE 
EXISTS ( SELECT 1 FROM mjr_agent agnt WHERE agnt.agent_group = 0 AND (txi.src_id = agnt.code OR txi.dest_id = agnt.code) ) 

2. Использование с двумя строками IN Пункт [Среднее время запроса: 0,37 с]

SELECT count(txi.id) FROM mjr_transaction_item txi
WHERE 
txi.src_id IN ( SELECT agnt.code FROM mjr_agent agnt WHERE agnt.agent_group = 0 ) 
OR txi.dest_id IN ( SELECT agnt.code FROM mjr_agent agnt WHERE agnt.agent_group = 0 )

3. Использование с шаблоном INNNER JOIN [Среднее время запроса: 2,9 с]

SELECT count(DISTINCT(txi.id)) FROM mjr_transaction_item txi
INNER JOIN mjr_agent agnt ON agnt.code = txi.src_id OR agnt.code = txi.dest_id
WHERE 
agnt.agent_group = 0

Итак, я выбрал второй вариант.

0 голосов
/ 12 июня 2018

Конкатенация столбцов вместе в некоторой форме - это хак, но когда продукт не поддерживает полусоединения для более чем одного столбца, иногда у вас нет выбора.

Пример того, где решение внутреннего / внешнего соединения не будет работать:

select * from T1 
 where <boolean expression>
   and (<boolean expression> OR (ColA, ColB) in (select A, B ...))
   and <boolean expression>
   ...

Когда запросы не являются тривиальными по своей природе, иногда у вас нет доступа к базовой таблице, установленной для выполнения регулярных внутренних / внешних объединений.

Если вы используете этот «хак», при объединении полей просто обязательно добавьте достаточное количество разделителя между ними, чтобы избежать неправильной интерпретации, например, ColA + ":-:" + ColB

0 голосов
/ 23 апреля 2018

Запрос:

select ord_num, agent_code, ord_date, ord_amount
from orders
where (agent_code, ord_amount) IN
(SELECT agent_code, MIN(ord_amount)
FROM orders 
GROUP BY agent_code);

запрос выше работал у меня в MySQL. см. следующую ссылку ->

https://www.w3resource.com/sql/subqueries/multiplee-row-column-subqueries.php

0 голосов
/ 24 октября 2017

Мы можем просто сделать это.

   select *
   from 
    table1 t, CRM_VCM_CURRENT_LEAD_STATUS c
    WHERE  t.CM_PLAN_ID = c.CRM_VCM_CURRENT_LEAD_STATUS
    and t.Individual_ID = c.Individual_ID
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...