Использование кортежей в предложении SQL «IN» - PullRequest
46 голосов
/ 04 ноября 2011

У меня есть таблица, содержащая поля group_id и group_type, и я хочу запросить в таблице все записи, имеющие любой кортеж ( идентификатор группы , тип группы ) из спискакортежи.Например, я хочу иметь возможность сделать что-то вроде:

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

Очень похожий вопрос уже задавался по адресу: с использованием кортежей в sql в пункте , но предлагаемое там решение предполагаетсписок кортежей должен быть выбран из другой таблицы.В моем случае это не работает, если значения кортежей жестко заданы.

Одним из решений является использование конкатенации строк:

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

Но проблема в том, что таблица довольно большая иВыполнение конкатенации и преобразования строк для каждой записи будет очень дорогим.

Любое предложение?

Ответы [ 8 ]

52 голосов
/ 04 ноября 2011

При очень незначительной настройке (замените двойные кавычки на одинарные и добавьте ключевое слово VALUES), предложенный вами синтаксис является допустимым стандартным синтаксисом SQL-92, т.е.

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

К сожалению, MSFT не добавил егов SQL Server и считают его «незапланированной» функцией .

FWIW PostgreSQL и Sqlite являются примерами продуктов SQL, поддерживающих этот синтаксис.

24 голосов
/ 04 ноября 2011

В 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               
             )
10 голосов
/ 04 ноября 2011

Почему бы не построить операторы 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)

Конечно, он не выглядит так красиво и аккуратно, как пример вашей концепции, но он сделает свою работу (и если бы вы IN с кортежами действительно существовали, он бы, скорее всего, реализовал это точно так же и под покровами).

7 голосов
/ 04 ноября 2011

Вы можете использовать общее табличное выражение, чтобы представить, что эти кортежи находятся в другой таблице:

;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)
3 голосов
/ 04 ноября 2011

При использовании этого решения это должно работать:

SELECT *
FROM mytable m
WHERE EXISTS (
   SELECT * FROM (
   SELECT "1234-567" group_id, 2 group_type UNION ALL
   SELECT "4321-765", 3 UNION ALL
   SELECT "1111-222", 5) [t]
   WHERE m.group_id = t.group_id AND m.group_type = t.group_type) 

Кстати, вам, вероятно, следует использовать CTE для создания этой внутренней таблицы.

0 голосов
/ 31 мая 2019
select * from table_name where 1=1 and (column_a, column_b) in ((28,1),(25,1))
0 голосов
/ 07 декабря 2018

У меня была похожая проблема, но моя коллекция кортежей была динамической - она ​​была отправлена ​​на SQL Server в параметре запроса. Я придумал следующее решение:

  1. Передать кортеж как XML:

    DECLARE @tuplesXml xml = '<tuples><tuple group-id="1234-567" group-type="2"/><tuple group-id="4321-765" group-type="3"/></tuples>';
    
  2. Внутреннее объединение таблицы, которую вы хотите фильтровать, с помощью узлов XML:

    SELECT t.* FROM mytable t
    INNER JOIN @tuplesXml.nodes('/tuples/tuple') AS tuple(col)
    ON tuple.col.value('./@group-id', 'varchar(255)') = t.group_id
    AND tuple.col.value('./@group-type', 'integer') = t.group_type
    

Кажется, в моей ситуации это работает нормально, что немного сложнее, чем описано в вопросе.

Имейте в виду, что необходимо использовать t.* вместо *, а таблицу, возвращаемую методом nodes, необходимо использовать для псевдонима (в данном случае tuple(col)).

0 голосов
/ 12 ноября 2014

Вот еще одно решение для кортежей с использованием объединения:

SELECT 
  *
FROM mytable m
JOIN
(
   SELECT "1234-567" group_id, 2 group_type 
   UNION ALL SELECT "4321-765", 3 
   UNION ALL SELECT "1111-222", 5
) [t]
ON m.group_id = t.group_id 
AND m.group_type = t.group_type
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...