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
ВНИМАНИЕ О РЕШЕНИЯХ:
МНОГИЕ СУЩЕСТВУЮЩИЕ РЕШЕНИЯ ДАЮТ НЕПРАВИЛЬНЫЙ ВЫХОД, ЕСЛИ СТРОКИ НЕ УНИКАЛЬНЫ
Если вы являетесь единственным человеком, создающим таблицы, это может не относиться к делу, но несколько решений приведут к разному количеству выходных строк из рассматриваемого кода, если одна из таблиц может не содержать уникальных строк.
ПРЕДУПРЕЖДЕНИЕ О ЗАДАЧЕ ПРОБЛЕМЫ:
В НЕСКОЛЬКИХ КОЛОННАХ НЕ СУЩЕСТВУЕТ, ВНИМАТЕЛЬНО ПУНИТЕ, ЧТО ВЫ ХОТИТЕ
Когда я вижу вход с двумя столбцами, я могу представить, что это означает две вещи:
- Значения столбца a и столбца b появляются в другой таблице независимо
- Значения столбца 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
Самые распространенные ошибки:
- Присоединение непосредственно к T2, без безопасного подзапроса. В результате чего возникает риск дублирования)
- SELECT * (гарантированно получить столбцы из T2)
- ВЫБРАТЬ c (не гарантирует, что ваш столбец будет приходить и всегда будет поступать из T1)
- Нет 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)
Это было бы довольно медленным. Невозможно использовать в программировании, но если вы просто запрашиваете подтверждение того, что что-то может быть использовано.