Заказ по порядку значений в предложении 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
Обратите внимание, что я также допускаю дублирование.