Заказ по порядку значений в предложении SQL IN()

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

Проблема в том, что у меня есть 2 запроса, один из которых получает все ID, а второй - всю информацию. Первый создает порядок идентификаторов, которые я хочу, чтобы второй заказывал. Идентификаторы помещаются в предложение IN() в правильном порядке.

Итак, это будет что-то вроде (чрезвычайно упрощенного):

SELECT id FROM table1 WHERE ... ORDER BY display_order, name

SELECT name, description, ... WHERE id IN ([id from first])

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

Одно из решений, которое я нашел, состоит в том, чтобы поместить все идентификаторы в временную таблицу с автоматически увеличивающимся полем, которое затем объединяется во второй запрос.

Есть ли лучший вариант?

Примечание.. Когда первый запрос запускается "пользователем", а второй выполняется в фоновом режиме, нет возможности объединить запрос 2 в 1 с использованием подзапросов.

Я использую MySQL, но я думаю, было бы полезно, если бы он заметил, какие опции существуют и для других БД.

Ответ 1

Используйте MySQL FIELD():

SELECT name, description, ...
FROM ...
WHERE id IN([ids, any order])
ORDER BY FIELD(id, [ids in order])

FIELD() вернет индекс первого параметра, который будет равен первому параметру (кроме самого первого параметра).

FIELD('a', 'a', 'b', 'c')

вернет 1

FIELD('a', 'c', 'b', 'a')

вернет 3

Это будет делать именно то, что вы хотите, если вы вставляете идентификаторы в предложение IN() и FIELD() в том же порядке.

Ответ 2

Узнайте, как получить отсортированные данные.

SELECT ...
  FROM ...
 WHERE zip IN (91709,92886,92807,...,91356)
   AND user.status=1
ORDER 
    BY provider.package_id DESC 
     , FIELD(zip,91709,92886,92807,...,91356)
LIMIT 10

Ответ 3

Два решения, которые spring:

  • order by case id when 123 then 1 when 456 then 2 else null end asc

  • order by instr(','||id||',',',123,456,') asc

(instr() от Oracle, возможно, у вас есть locate() или charindex() или что-то в этом роде)

Ответ 4

Предложение IN описывает набор значений, а наборы не имеют порядка.

Ваше решение с соединением и заказом в столбце display_order является наиболее правильным решением; все остальное, вероятно, связано с СУБД (или делает некоторые вещи с функциями OLAP в стандартном SQL). Разумеется, соединение является наиболее переносимым решением (хотя генерация данных со значениями display_order может быть проблематичной). Обратите внимание, что вам может потребоваться выбрать столбцы упорядочения; который раньше требовался в стандартном SQL, хотя я считаю, что он был расслаблен, как правило, некоторое время назад (возможно, еще как SQL-92).

Ответ 5

Ans для сортировки данных.

SELECT ...
FROM ...
ORDER  BY FIELD(user_id,5,3,2,...,50)  LIMIT 10

Ответ 6

Используйте MySQL FIND_IN_SET:

  SELECT * 
    FROM table_name 
   WHERE id IN (..,..,..,..) 
ORDER BY FIND_IN_SET (coloumn_name, .., .., ..);

Ответ 7

Для Oracle используется решение John с использованием функции instr(). Здесь немного другое решение, которое сработало - SELECT id FROM table1 WHERE id IN (1, 20, 45, 60) ORDER BY instr('1, 20, 45, 60', id)

Ответ 8

SELECT ORDER_NO, DELIVERY_ADDRESS 
from IFSAPP.PURCHASE_ORDER_TAB 
where ORDER_NO in ('52000077','52000079','52000167','52000297','52000204','52000409','52000126') 
ORDER BY instr('52000077,52000079,52000167,52000297,52000204,52000409,52000126',ORDER_NO)

отлично работает

Ответ 9

Если вы хотите выполнить произвольную сортировку по запросу, используя значения, введенные в запросе, в MS SQL Server 2008 +, это можно сделать, создав таблицу "на лету" и сделав соединение таким образом (с использованием номенклатуры от OP).

SELECT table1.name, table1.description ... 
FROM (VALUES (id1,1), (id2,2), (id3,3) ...) AS orderTbl(orderKey, orderIdx) 
LEFT JOIN table1 ON orderTbl.orderKey=table1.id
ORDER BY orderTbl.orderIdx

Если вы замените оператор VALUES на что-то другое, что делает то же самое, но в ANSI SQL, то это должно работать с любой базой данных SQL.

Примечание: Второй столбец в созданной таблице (orderTbl.orderIdx) необходим при запросе наборов записей больше 100 или около того. Первоначально у меня не было столбца orderIdx, но обнаружил, что с наборами результатов больше 100 я должен был явно сортировать по этому столбцу; в SQL Server Express 2014 в любом случае.

Ответ 10

Моя первая мысль заключалась в том, чтобы написать один запрос, но вы сказали, что это невозможно, потому что один запускается пользователем, а другой запущен в фоновом режиме. Как вы храните список идентификаторов для перехода от пользователя к фоновому процессу? Почему бы не поместить их во временную таблицу со столбцом, чтобы обозначить заказ.

Итак, как насчет этого:

  • Бит пользовательского интерфейса запускается и вставляет значения в новую таблицу, которую вы создаете. Он будет вставлять идентификатор, позицию и некоторый идентификатор номера задания)
  • Номер задания передается фоновому процессу (вместо всех идентификаторов)
  • Фоновый процесс делает выбор из таблицы на шаге 1 и вы присоединяетесь, чтобы получить другую требуемую информацию. Он использует номер задания в предложении WHERE и заказывает столбец позиции.
  • Фоновый процесс, по окончании, удаляется из таблицы на основе идентификатора задания.

Ответ 11

Я думаю, вам удастся сохранить ваши данные таким образом, что вы просто выполните объединение, и это будет идеально, поэтому никаких хаков и сложных вещей не происходит.

У меня есть, например, список последних треков "Недавно воспроизведенный", на SQLite я просто делаю:

SELECT * FROM recently NATURAL JOIN tracks;

Ответ 12

Сделайте снимок:

SELECT name, description, ...
WHERE id IN
    (SELECT id FROM table1 WHERE...)
ORDER BY
    (SELECT display_order FROM table1 WHERE...),
    (SELECT name FROM table1 WHERE...)

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

Ответ 13

Я просто пытался это сделать, это MS SQL Server, где у нас нет FIELD():

SELECT table1.id
... 
INNER JOIN
    (VALUES (10,1),(3,2),(4,3),(5,4),(7,5),(8,6),(9,7),(2,8),(6,9),(5,10)
    ) AS X(id,sortorder)
        ON X.id = table1.id
    ORDER BY X.sortorder

Обратите внимание, что я также допускаю дублирование.