3

假设您有一个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 扩展中?如果不是,为什么(会欣赏任何猜测)?

4

5 回答 5

3

这两个都是有效的 ISO/ANSI 完整 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 语法(它在 SQL-Server 2008 中不起作用,因为NATURAL JOIN):

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 中有一个类似的问题,有各种其他的方法来表述这个问题:
选择两个列在集合中的位置

于 2012-01-19T00:00:15.997 回答
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 行。您可以在此页面上阅读有关 T-SQL 对表文字的支持的更多信息。

编辑:此页面表明此构造也适用于 PostgreSQL。

于 2012-01-18T23:11:44.253 回答
2

小心如何解释这一点。鲨鱼的答案会起作用,但会回来

TaxID        AccountNumber
1234         8765
1234         7654
2345         8765
2345         7654

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

WHERE (taxId'1234' and accountnumber='8765') OR 
      (taxid='2345' and accountNumber='7654')
于 2012-01-18T22:57:27.607 回答
2

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

例如

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
于 2012-01-18T23:00:45.253 回答
1

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

不建议连接这些值,即使使用不常见的分隔符,也总是存在一些不正确匹配自由输入的文本值的风险。最好不要养成这个习惯。

于 2013-10-17T18:46:15.890 回答