SQL WHERE IN子句中的多键

时间:2012-01-18 22:49:39

标签: sql row-value-expression

假设您有Accounts表,其中ID列是PK,TaxID+AccountNumber是唯一约束:

select * from Accounts where ID in (100, 101)

现在您想使用自然键进行类似的查询:

select * from Accounts 
where {TaxID, AccountNumber} in 
  ({"0123456", "2000897"}, {"0125556", "2000866"})

所以这涉及元组并且看起来非常合理。有可能用ANSI SQL表达某种方式吗?也许在某些特定的SQL扩展?如果没有,为什么(会欣赏任何推测)?

5 个答案:

答案 0 :(得分:3)

如果您使用的是T-SQL,那么看起来有点像您的假设查询的选项就是使用表格文字,如下所示:

select * 
from Accounts a
inner join (values('0123456', '2000897'),('0125556', '2000866')) 
    as v(TaxID, AccountNumber) 
    on a.TaxID = v.TaxID and a.AccountNumber = v.AccountNumber

在此创建一个名为v的表格文字,其中包含字段TaxIDAccountNumber。现在,您可以在两个字段上加入表格文字以获得所需的结果。需要注意的是,表格文字只能包含1000行。您可以在this page上阅读有关表格文字的T-SQL支持的更多信息。

编辑:this page表示此构造也适用于PostgreSQL。

答案 1 :(得分:3)

这两种语法都是有效的ISO / ANSI Full SQL-92语法:

SELECT a.* 
FROM Accounts a
  INNER JOIN
    ( VALUES('0123456', '2000897'), ('0125556', '2000866')
    ) AS v(TaxID, AccountNumber) 
  ON (a.TaxID, a.AccountNumber) = (v.TaxID, v.AccountNumber)

SELECT * 
FROM Accounts a
WHERE (a.TaxID, a.AccountNumber) IN 
    ( VALUES ('0123456', '2000897'), ('0125556', '2000866') )

但我认为它们中的任何一个都不适用于任何当前的DBMS。


这也是有效的完整SQL-92语法(由于NATURAL JOIN,它在SQL-Server 2008中不起作用):

SELECT a.* 
FROM Accounts a
  NATURAL JOIN
    ( VALUES('0123456', '2000897'), ('0125556', '2000866')
    ) AS v(TaxID, AccountNumber) 

这也是有效的SQL(不确定它是否在92规范或更高版本中) - 并且就是你所拥有的(但使用括号,而不是大括号)。
它受MySQL,Postgres,DB2(但不是SQL Server)的支持:

SELECT a.* 
FROM Accounts a
WHERE (TaxID, AccountNumber) IN
    ( ('0123456', '2000897'), ('0125556', '2000866') )
  ;

在DBA.SE中也有类似的问题,还有其他各种方法来制定这个问题:
 的 selecting where two columns are in a set

答案 2 :(得分:2)

小心如何代表这一点。 Shark的答案会有效,但会返回

TaxID        AccountNumber
1234         8765
1234         7654
2345         8765
2345         7654

可能不是您想要的...例如,如果您只需要税号1234的帐号8765和税号2345的7654,则需要这样的WHERE子句:

WHERE (taxId'1234' and accountnumber='8765') OR 
      (taxid='2345' and accountNumber='7654')

答案 3 :(得分:2)

粗略的方法是将2个值连接在一起..

e.g。

SELECT *
FROM Accounts
WHERE CAST(TaxID AS VARCHAR(10)) + '-' + CAST(AccountNumber AS VARCHAR(10)) 
IN ('0123456-2000897', '......', ....)

但是,在例如SQL Server,这将无法使用索引。

您可以添加一个计算列,将两个值组合成1,然后匹配:

SELECT * FROM Accounts WHERE MyComputedColumn IN ('0123456-2000897', ....)


或者,您可以这样做:

SELECT a.*
FROM Accounts a
    JOIN 
    (
        SELECT '0123456' AS TaxID, '2000897' AS AccountNumber
        UNION ALL
        SELECT '0125556', '2000866'
    ) x ON a.TaxID = x.TaxID AND a.AccountNumber = x.Number

答案 4 :(得分:1)

在Oracle SQL中,您只需将括号替换为原始帖子中的大括号“{}”(第二个示例)。可能不是ANSII标准,但它很接近,而且工作正常。

建议不要连接这些值,即使使用不常见的分隔符,也总是会有一些微小的风险,即错误地匹配自由输入的文本值。最好不要养成这个习惯。