Porządkowanie według kolejności wartości w klauzuli SQL IN()

Zastanawiam się, czy istnieje (być może lepszy sposób) porządkowanie według kolejności wartości w klauzuli IN ().

Problem polega na tym, że mam 2 zapytania, jeden, który pobiera wszystkie identyfikatory, a drugi, który pobiera wszystkie informacje. Pierwszy tworzy kolejność identyfikatorów, które chcę, aby drugi zamówił. Identyfikatory są umieszczane w klauzuli IN() W odpowiedniej kolejności.

Więc byłoby to coś w stylu (bardzo uproszczonym):

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

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

Problem polega na tym, że drugie zapytanie nie zwraca wyników w tej samej kolejności, w jakiej identyfikatory są umieszczane w klauzuli IN ().

Jednym z rozwiązań, które znalazłem, jest umieszczenie wszystkich identyfikatorów w tabeli temp z polem automatycznego zwiększania, które jest następnie łączone z drugim zapytaniem.

Czy jest lepsza opcja?

Notatka: jako że pierwsze zapytanie jest uruchamiane "przez użytkownika", a drugie jest uruchamiane w procesie w tle, nie ma możliwości połączenia 2 w 1 zapytania przy użyciu podrzędnych zapytań.

Używam MySQL, ale Myślę, że może być przydatne, aby zauważyć, jakie opcje są również dla innych DBs.

Author: Patrick Kostjens, 2008-12-29

13 answers

Użyj MySQL ' s FIELD() funkcja:

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

FIELD() zwróci indeks pierwszego parametru, który jest równy pierwszemu parametrowi (innemu niż sam pierwszy parametr).

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

Zwróci 1

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

Zwróci 3

To zrobi dokładnie to, co chcesz, Jeśli wkleisz identyfikatory do klauzuli IN() i funkcji FIELD() w tej samej kolejności.

 170
Author: ʞɔıu,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2016-05-30 17:34:12

Zobacz jak sortować dane.

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
 13
Author: Pradeep Singh,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2011-12-01 09:34:20

Dwa rozwiązania, które przychodzą na myśl:

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

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

(instr() jest z Oracle; może masz locate() lub charindex() lub coś w tym stylu)

 11
Author: John Nilsson,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2008-12-29 06:57:53

Ans, aby uzyskać posortowane dane.

SELECT ...
FROM ...
ORDER  BY FIELD(user_id,5,3,2,...,50)  LIMIT 10
 5
Author: Gulshan Prajapati,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2014-01-30 09:27:47

Jeśli chcesz wykonać dowolne sortowanie na zapytaniu za pomocą wartości wprowadzonych przez zapytanie w MS SQL Server 2008 + , można to zrobić, tworząc tabelę w locie i wykonując podobne połączenie (używając nomenklatury z 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

Jeśli zamienisz polecenie VALUES na coś innego, co robi to samo, ale w ANSI SQL, to powinno to działać na dowolnej bazie danych SQL.

Uwaga: Druga kolumna w utworzonej tabeli (orderTbl.orderIdx) jest konieczne przy zapytaniu zestawy rekordów większe niż 100 lub więcej. Początkowo nie miałem kolumny orderIdx, ale okazało się, że z zestawami wyników większych niż 100 musiałem wyraźnie sortować według tej kolumny; w SQL Server Express 2014 tak czy inaczej.

 5
Author: Ian,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2015-12-08 22:50:44

Klauzula IN opisuje zbiór wartości, a zestawy nie mają porządku.

Twoje rozwiązanie z join, a następnie zamówienie na kolumnie display_order jest najbardziej poprawnym rozwiązaniem; Wszystko inne jest prawdopodobnie specyficznym dla DBMS hack(lub robi coś z funkcjami OLAP w standardowym SQL). Z pewnością join jest najbardziej przenośnym rozwiązaniem (choć generowanie danych z wartościami display_order może być problematyczne). Zauważ, że może być konieczne wybranie kolumn zamawiających; które używane do być wymogiem w standardowym SQL, choć uważam, że był zrelaksowany z reguły jakiś czas temu (może tak dawno temu, jak SQL-92).

 4
Author: Jonathan Leffler,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2008-12-29 07:02:59

W przypadku Oracle rozwiązanie Johna za pomocą funkcji instr() działa. Oto nieco inne rozwiązanie, które zadziałało - SELECT id FROM table1 WHERE id IN (1, 20, 45, 60) ORDER BY instr('1, 20, 45, 60', id)

 2
Author: V Patel,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2012-05-31 23:54:19
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)

Pracował naprawdę świetnie

 2
Author: Ravi Ranjan,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2012-07-05 11:43:15

Użyj MySQL FIND_IN_SET function:

  SELECT * 
    FROM table_name 
   WHERE id IN (..,..,..,..) 
ORDER BY FIND_IN_SET (coloumn_name, .., .., ..);
 2
Author: Sarthak Sawhney,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2015-06-21 16:34:32

Moją pierwszą myślą było napisanie pojedynczego zapytania, ale powiedziałeś, że nie jest to możliwe, ponieważ jedno jest uruchamiane przez użytkownika, a drugie jest uruchamiane w tle. Jak przechowujesz listę identyfikatorów, które mają zostać przekazane od użytkownika do procesu w tle? Dlaczego nie umieścić ich w tymczasowej tabeli z kolumną, aby określić kolejność.

Więc co powiesz na to:

  1. bit interfejsu użytkownika uruchamia i wstawia wartości do nowej utworzonej tabeli. Wstawia id, pozycję i jakieś zadanie numer identyfikacyjny)
  2. numer zadania jest przekazywany do procesu w tle (zamiast wszystkich identyfikatorów)
  3. proces w tle wykonuje select z tabeli w kroku 1, a Ty dołączasz, aby uzyskać inne wymagane informacje. Używa numeru zadania w klauzuli WHERE i zleceń w kolumnie position.
  4. proces w tle, po zakończeniu, usuwa z tabeli na podstawie identyfikatora zadania.
 1
Author: WW.,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2008-12-28 23:50:39

Myślę, że powinieneś przechować swoje dane w taki sposób, aby po prostu zrobić połączenie i będzie idealne, więc nie ma hacków i skomplikowanych rzeczy się dzieje.

Mam na przykład listę" ostatnio odtwarzanych " idów utworów, na SQLite po prostu robię:

SELECT * FROM recently NATURAL JOIN tracks;
 1
Author: kroe,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2015-10-23 18:32:56

Daj temu szansę:

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 prawdopodobnie będzie wymagało trochę poprawek, aby skorelowane zapytania działały poprawnie, ale podstawowa zasada powinna być dźwiękowa.

 0
Author: chaos,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2008-12-28 22:17:27

Właśnie próbowałem zrobić to jest MS SQL Server gdzie nie mamy pola ():

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

Zauważ, że ja również zezwalam na powielanie.

 0
Author: Tony,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2016-08-16 10:13:33