SQL WHERE.. IN в нескольких столбцах

Мне нужно выполнить следующий запрос в 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 столбец. Как сравнить два или более столбца с другим внутренним SELECT?

Ответ 1

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

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

Ответ 2

Вместо этого вы хотите использовать синтаксис 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)

Ответ 3

Простое условие 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 также будет включать столбцы из таблиц ограничения строк

Ответ 4

select * from tab1 where (col1,col2) in (select col1,col2 from tab2)

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

select * from tab1
where (col1, NVL(col2, '---') in (select col1, NVL(col2, '---') from tab2)

Ответ 5

Зачем использовать WHERE EXISTS или DERIVED TABLES, когда вы можете просто выполнить нормальное внутреннее соединение:

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. *.

Ответ 6

ВНИМАНИЕ О РЕШЕНИЯХ:

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

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

ПРЕДУПРЕЖДЕНИЕ О ЗАДАЧЕ ПРОБЛЕМЫ:

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

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

  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)

ВНУТРЕННЕЕ СОЕДИНЕНИЕ (технически это можно сделать безопасным, но часто этого не делается)

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

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. ВЫБРАТЬ c (не гарантирует, что ваш столбец будет приходить и всегда будет поступать из T1)
  4. Нет DISTINCT или DISTINCT в неправильном месте

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

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

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

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


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

Ответ 7

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.Using с двумя линиями IN пункте [Среднее время запроса: 0.37s]

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

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

Ответ 8

Если вы хотите использовать одну таблицу, используйте следующий запрос

SELECT S.* 
FROM Student_info S
  INNER JOIN Student_info UT
    ON S.id = UT.id
    AND S.studentName = UT.studentName
where S.id in (1,2) and S.studentName in ('a','b')

и данные таблицы, как следует

id|name|adde|city
1   a   ad  ca
2   b   bd  bd
3   a   ad  ad
4   b   bd  bd
5   c   cd  cd

Затем выполните следующие действия:

id|name|adde|city
1   a   ad  ca
2   b   bd  bd

Ответ 9

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

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

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

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

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

Ответ 10

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

   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

Ответ 11

Запрос:

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

Ответ 12

Я упростил этот путь

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

Надеюсь, что эта помощь:)

Ответ 13

Простой и неправильный способ заключается в объединении двух столбцов с использованием + или конкатенации и создании одного столбца.

Select *
from XX
where col1+col2 in (Select col1+col2 from YY)

Это было бы довольно медленным. Невозможно использовать в программировании, но если вы просто запрашиваете подтверждение того, что что-то может быть использовано.