我需要在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个或更多的列与另一个内部选择?


取而代之的是使用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)

你可以从子查询中创建一个派生表,并将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

简单的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会在输出中给出多行,因此需要distinct。这通常使EXISTS更有效。

注意带有JOIN的SELECT *还包括行限制表中的列


为什么使用WHERE EXISTS或DERIVED表,当你可以只做一个普通的内部连接:

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


我觉得这样更容易

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 
) 

希望这对你有所帮助:)


简单而错误的方法是使用+或连接两列并生成一列。

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

这会偏离轨道,很慢。不能在编程中使用,但如果你只是查询验证一些东西可能会被使用。


如果你想要一个表,然后使用以下查询

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

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)

我们可以简单地这么做。

   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

查询:

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


以某种形式将列连接在一起是一种“hack”,但是当产品不支持多个列的半连接时,有时您别无选择。

内部/外部连接解决方案不工作的例子:

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

当查询在本质上并不简单时,有时您无法访问基表集来执行常规的内/外连接。

如果你确实使用了这个“黑客”,当你组合字段时,请确保在它们之间添加足够的分隔符以避免误解,例如ColA + ":-:" + ColB


Postgres SQL  : version 9.6
Total records on tables : mjr_agent = 145, mjr_transaction_item = 91800

1.使用EXISTS[平均查询时间:1.42s]

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.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.使用inner JOIN模式[平均查询时间:2.9s]

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

所以,我选择了第二种选择。


关于解决方案的警告:

如果行不是唯一的,许多现有的解决方案将给出错误的输出

如果您是唯一创建表的人,这可能无关紧要,但是当其中一个表可能不包含唯一行的时候,一些解决方案将从相关代码中给出不同数量的输出行。

关于问题语句的警告:

在与多列不存在的情况下,仔细想想你想要什么

当我看到一个in有两列时,我可以想象它意味着两件事:

列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 server在内的大多数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

最常见的错误:

直接在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 server会自动做到这一点。


总结一下:通常在SQL中有很多方法可以做到这一点,使用安全的选择将避免意外,并为您节省时间和长远的发展。


*** t-sql ***

我使用string_agg作为廉价的hack来获得cheep上的一些伪规范化。(好吧,它是多路复用的,我知道它很糟糕,我用一些精心制作的80年代风格的盒子图来补偿你的痛苦,享受吧!~)

这里有一个例子(想出名字替代品很有趣:D)

select 
    vendorId,   
    affiliate_type_code, 
    parent_vendor_id,
    state_abbr,
    county_abbr,
    litigation_activity_indicator,
    string_agg(employee_id,',') as employee_ids,
    string_agg(employee_in_deep_doodoo,',') as 'employee-inventory connections'
from (
    select distinct top 10000 -- so I could pre-order my employee id's - didn't want mixed sorting in those concats
    mi.missing_invintory_identifier as rqid,
    vendorId,   
    affiliate_type_code, 
    parent_vendor_id,
    state_abbr,
    county_abbr,
    litigation_activity_indicator,
    employee_identifier as employee_id,
    concat(employee_identifier,'-',mi.missing_invintory_identifier) as employee_in_deep_doodoo
    from 
        missing_invintory as mi 
        inner join vendor_employee_view as ev
        on mi.missing_invintory_identifier = ev.missing_invintory_identifier        
    where ev.litigation_activity_indicator = 'N'
    order by employee_identifier desc

)  as x
    group by 
    vendorId,   
    affiliate_type_code, 
    parent_vendor_id,
    state_abbr,
    county_abbr,
    litigation_activity_indicator
    having count(employee_id) > 1



┏━━━━━━━━━━┳━━━━━━━━━━━━━━━━┳━━━━━━━━━━━━━━━━━━┳━━━━━━━━━━━━┳━━━━━━━━━━━━━━━━━━━┳━━━━━━━━━━━━━━━━━━━━━━┳━━━━━━━━━━━━━━━━━━━━━┳━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┓
┃ vendorId ┃ affiliate_type ┃ parent_vendor_id ┃ state_abbr ┃ county_abbr       ┃ litigation_indicator ┃ employee_ids        ┃ employee-inventory connections ┃
┣━━━━━━━━━━╋━━━━━━━━━━━━━━━━╋━━━━━━━━━━━━━━━━━━╋━━━━━━━━━━━━╋━━━━━━━━━━━━━━━━━━━╋━━━━━━━━━━━━━━━━━━━━━━╋━━━━━━━━━━━━━━━━━━━━━╋━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┫
┃      123 ┃ EXP            ┃               17 ┃ CA         ┃ SDG               ┃ N                    ┃ 112358,445678       ┃ 112358-1212,1534490-1212       ┃
┣━━━━━━━━━━╋━━━━━━━━━━━━━━━━╋━━━━━━━━━━━━━━━━━━╋━━━━━━━━━━━━╋━━━━━━━━━━━━━━━━━━━╋━━━━━━━━━━━━━━━━━━━━━━╋━━━━━━━━━━━━━━━━━━━━━╋━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┫
┃     4567 ┃ PRI            ┃              202 ┃ TX         ┃ STB               ┃ Y                    ┃ 998754,332165       ┃ 998754-4545,332165-4545        ┃
┗━━━━━━━━━━┻━━━━━━━━━━━━━━━━┻━━━━━━━━━━━━━━━━━━┻━━━━━━━━━━━━┻━━━━━━━━━━━━━━━━━━━┻━━━━━━━━━━━━━━━━━━━━━━┻━━━━━━━━━━━━━━━━━━━━━┻━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┛