在SQL"IN"子句中使用元组

Raf*_*fid 51 sql sql-server tuples row-value-expression

我有一个包含字段group_id和group_type的表,我想从表中查询具有元列表中任何元组(组ID,组类型)的所有记录.例如,我希望能够做到这样的事情:

SELECT *
FROM mytable
WHERE (group_id, group_type) IN (("1234-567", 2), ("4321-765", 3), ("1111-222", 5))
Run Code Online (Sandbox Code Playgroud)

一个非常类似的问题已经在:使用sql in子句中的元组,但是在那里提出的解决方案假定元组列表是从另一个表中获取的.这在我的情况下不起作用是元组值是硬编码的.

一种解决方案是使用字符串连接:

SELECT *
FROM mytable
WHERE group_id + STR(group_type, 1) IN ("1234-5672", "4321-7653", "1111-2225")
Run Code Online (Sandbox Code Playgroud)

但问题是该表非常大,并且对每个记录执行字符串连接和转换将非常昂贵.

有什么建议吗?

one*_*hen 57

给出一个非常小的调整(用单引号替换双引号并添加VALUES关键字),您提出的语法是有效的标准SQL-92语法,即

SELECT *
  FROM mytable
 WHERE (group_id, group_type) IN (
                                  VALUES ('1234-567', 2), 
                                         ('4321-765', 3), 
                                         ('1111-222', 5)
                                 );
Run Code Online (Sandbox Code Playgroud)

遗憾的是,MSFT尚未将其添加到SQL Server并将其视为"未计划"功能.

FWIW PostgreSQL和Sqlite是支持此语法的SQL产品的示例.

  • @static_rtti:我知道PostgreSQL和Sqlite支持语法,而Oracle和mySQL不支持。PS的要点:这些是SQL产品(或“ SQL DBMS”或类似产品)的示例。数据库是用户使用SQL产品创建的变量。例如,有一个名为“飞机”(逻辑)的数据库可保存在笔记本电脑的磁盘上,我可以操纵此变量,该变量本身包含名为“ mytable”的表(逻辑)。“飞机”数据库不支持上述语法,因为它受我用来创建和修改它的SQL产品(MSSQL)的限制。 (2认同)

Mik*_*son 25

在SQL Server 2008中,您可以这样做:

select *
from mytable as T
where exists (select *
              from (values ('1234-567', 2), 
                           ('4321-765', 3), 
                           ('1111-222', 5)) as V(group_id, group_type)
              where T.group_id = V.group_id and
                    T.group_type = V.group_type               
             )
Run Code Online (Sandbox Code Playgroud)

  • 或者:`where where(选择T.group_id,T.group_type INTERSECT select*from(values('1234-567',2),...)作为V(group_id,group_type))`. (3认同)
  • @MikaelEriksson这也可行:`where not exists(选择T.group_id,T.group_type EXCEPT select*from(values('1234-567',2),...)为V(group_id,group_type)); (2认同)

Cod*_*ian 11

为什么不构造OR语句?

SELECT *
FROM mytable 
WHERE (group_id = '1234-567' and group_type = 2)
    OR (group_id = '4321-765' and group_type = 3)
    OR (group_id = '1111-222' and group_type = 5)
Run Code Online (Sandbox Code Playgroud)

当然,它看起来并不像你的概念示例那样漂亮和整洁,但是它会完成这项工作(如果你IN确实存在元组,那么它最有可能在封面下以完全相同的方式实现它.

  • 好点子!唯一的问题是,如果你有一长串的元组列表. (2认同)

Dam*_*ver 7

您可以使用公用表表达式假装这些元组位于另一个表中:

;WITH Tuples as (
     select '1234-567' as group_id, 2 as group_type union all
     select '4321-765', 3 union all
     select '1111-222', 5
)
SELECT * /* TODO - Pick appropriate columns */
from mytable m where exists (
   select * from Tuples t
   where m.group_id = t.group_id and m.group_type = t.group_type)
Run Code Online (Sandbox Code Playgroud)

  • @Promather - 它就在那里因为`WITH`关键字可以有其他含义,并且为了引入CTE,它必须是一个语句的开头.分号确保前一个语句肯定会终止. (6认同)
  • 谢谢,但为什么在WITH子句之前有分号? (3认同)