SQL IN () 절의 값 순서에 따른 순서


154

IN () 절의 값 순서대로 정렬 할 수있는 방법이 있는지 궁금합니다.

문제는 두 개의 쿼리가 있다는 것입니다. 하나는 모든 ID를 가져오고 두 번째는 모든 정보를 검색합니다. 첫 번째는 두 번째로 주문하려는 ID의 순서를 만듭니다. ID는 IN () 절에 올바른 순서로 배치됩니다.

따라서 (매우 단순화 된) 것과 같습니다.

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

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

문제는 두 번째 쿼리가 ID를 IN () 절에 넣는 것과 같은 순서로 결과를 반환하지 않는다는 것입니다.

내가 찾은 한 가지 해결책은 모든 ID를 자동 증분 필드가있는 임시 테이블에 넣은 다음 두 번째 쿼리에 조인하는 것입니다.

더 나은 옵션이 있습니까?

참고 : 첫 번째 쿼리는 "사용자에 의해"실행되고 두 번째 쿼리는 백그라운드 프로세스에서 실행되므로 하위 쿼리를 사용하여 2 개를 1 개 쿼리로 결합 할 수있는 방법이 없습니다.

MySQL을 사용하고 있지만 다른 DB에도 어떤 옵션이 있는지 기록하는 것이 유용 할 수 있다고 생각합니다.

답변:


186

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을 반환합니다

이것은 id를 IN()절과 FIELD()함수에 같은 순서 로 붙여 넣으면 원하는 것을 정확하게 수행합니다 .


3
임의의 순서로 @Vojto 정렬은 정의에 따라 느립니다. 보장이 없기 때문에이 최선을 다하고 INFIELD동일한 매개 변수를 설정합니다. 추가 지식을 사용하면 프로그램 코드에서이 작업을 더 빠르게 수행 할 수 있습니다. 물론 서버 성능을 염두에두고 있다면 서버보다 클라이언트에이 부담을 가하는 것이 현명 할 수 있습니다.
ivan_pozdeev

1
무엇에 대해 sqlite?
fnc12 2016 년

15

정렬 된 데이터를 얻는 방법은 다음을 참조하십시오.

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

11

떠오르는 두 가지 솔루션 :

  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()Oracle에서이며, 어쩌면 당신이 locate()charindex()또는 같은)


MySQL의 경우 FIELD_IN_SET ()을 사용할 수도 있습니다. dev.mysql.com/doc/refman/5.0/en/…
Darryl Hein


6

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에서.


이 질문은 MySQL에 관한 것입니다 ... 쿼리가 MySQL에서 작동하는지 확실하지 않습니다.
Darryl Hein

2
@Darryl, 그렇지 않을 것입니다. 그러나이 게시물은 IN 절로 주문하는 방법에 대한 Google 검색의 최상위 결과로 표시되므로 여기에 게시 할 수 있으며 일반적인 방법론이 모든 ANSI 호환 SQL 서버에 적용됩니다 (VALUES 문을 표준으로 대체하십시오) 테이블을 만드는 방법).
Ian

참고이 나를 위해 일했다,하지만 난에 대한 참조를 교체 한 후에 만 orderTbl.orderKey, orderTbl.orderIndex에 의해 orderKey,orderIndex
피터

5
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)

정말 대단했다


Oracle에서 저를 위해 일했습니다. 빠르고 쉽습니다. 감사.
Menachem

4

IN 절은 값 세트를 설명하며 세트에는 순서가 없습니다.

조인 한 다음 display_order열에 주문한 솔루션이 가장 정확한 솔루션입니다. 다른 것은 아마도 DBMS 특정 해킹 일 것입니다 (또는 표준 SQL의 OLAP 함수로 작업을 수행하고 있음). 확실히, 조인은 가장 이식성이 뛰어난 솔루션입니다 ( display_order값으로 데이터를 생성하는 데 문제가있을 수 있음). 순서 열을 선택해야 할 수도 있습니다. 이전에는 표준 SQL에서 요구 사항 이었지만 이전에는 규칙으로 완화 된 것으로 생각합니다 (SQL-92만큼 오래 전).


2

Oracle의 경우 instr () 함수를 사용하는 John의 솔루션이 작동합니다. 작동하는 약간 다른 솔루션이 있습니다. SELECT id FROM table1 WHERE id IN (1, 20, 45, 60) ORDER BY instr('1, 20, 45, 60', id)



2

방금 FIELD ()가없는 MS SQL Server입니다.

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

복제도 허용됩니다.


1

내 첫 번째 생각은 단일 쿼리를 작성하는 것이었지만 사용자가 하나를 실행하고 다른 하나는 백그라운드에서 실행하기 때문에 불가능하다고 말했습니다. 사용자에서 백그라운드 프로세스로 전달할 ID 목록을 어떻게 저장합니까? 주문을 나타 내기 위해 열이있는 임시 테이블에 넣으십시오.

그럼 어떻습니까?

  1. 사용자 인터페이스 비트가 실행되어 사용자가 만든 새 테이블에 값을 삽입합니다. ID, 위치 및 일종의 작업 번호 식별자를 삽입합니다)
  2. 작업 번호는 모든 ID 대신 백그라운드 프로세스로 전달됩니다.
  3. 백그라운드 프로세스는 1 단계의 테이블에서 선택을 수행하고 필요한 다른 정보를 얻기 위해 참여합니다. WHERE 절의 작업 번호와 위치 열 순서를 사용합니다.
  4. 백그라운드 프로세스는 완료되면 작업 ID에 따라 테이블에서 삭제합니다.

1

나는 당신이 단순히 조인을 할 수있는 방식으로 데이터를 관리해야한다고 생각합니다. 그래서 해킹과 복잡한 일이 일어나지 않습니다.

예를 들어 SQLite에서 "최근에 재생 된"트랙 ID 목록이 있습니다.

SELECT * FROM recently NATURAL JOIN tracks;

1
인생이 그렇게 간단했으면 좋겠다 :)
Darryl Hein

0

이 기회를주세요 :

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

WHERE는 상관 서브 쿼리가 제대로 작동하도록 약간 조정해야하지만 기본 원칙은 적절해야합니다.


참고를 참조하십시오. 또한 언급 한 바와 같이 쿼리 예제는 매우 간단하므로 하위 쿼리를 사용하여 하나의 쿼리로 결합 할 수 없습니다.
Darryl Hein
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.