SQL IN()句の値の順序による順序付け


154

IN()句の値の順序で並べ替えるのに(おそらくより良い方法が)あるかどうか疑問に思っています。

問題は、2つのクエリがあることです。1つはすべてのIDを取得し、2つ目はすべての情報を取得します。1つ目は、2つ目で並べ替えたいIDの順序を作成します。IDはIN()句に正しい順序で配置されます。

だからそれは(非常に単純化された)のようなものになるでしょう:

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

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

問題は、2番目のクエリがIDがIN()句に入力されたのと同じ順序で結果を返さないことです。

私が見つけた1つの解決策は、自動インクリメントフィールドを持つ一時テーブルにすべてのIDを入れ、それを2番目のクエリに結合することです。

より良いオプションはありますか?

注:最初のクエリは「ユーザーによって」実行され、2番目のクエリはバックグラウンドプロセスで実行されるため、サブクエリを使用して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 2015

1
どうsqliteですか?
fnc12 2017年

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

思い浮かぶ2つのソリューション:

  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()オラクルからであり、多分あなたが持っているlocate()か、charindex()またはそのような何か)


MySQLの場合、FIELD_IN_SETは()を使用することもできます。dev.mysql.com/doc/refman/5.0/en/...
ダリル・ハインに


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データベースでも機能します。

注: 作成されたテーブルの2番目の列(orderTbl.orderIdx)は、100以上のレコードセットをクエリする場合に必要です。最初はorderIdx列がありませんでしたが、100より大きい結果セットでは、その列で明示的に並べ替える必要があることがわかりました。SQL Server Express 2014ではとにかく。


この質問はMySQLに関するものです...クエリがMySQLで機能するかどうかは不明です。
Darryl Hein、2015

2
@ダリル、そうじゃない。しかし、この投稿は、IN句による順序付け方法をグーグル検索したときに上位の結果として表示されるので、ここに投稿することもできます。一般的な方法は、すべてのANSI準拠SQLサーバーに適用されます(VALUESステートメントを標準に置き換えるだけです)テーブルを作成する方法)。
Ian

注、これは私のために働いたが、私はへの参照を交換した後にのみorderTbl.orderKeyorderTbl.orderIndexorderKeyorderIndex
ピーター

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 2015

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

私の最初の考えは単一のクエリを書くことでしたが、1つはユーザーによって実行され、もう1つはバックグラウンドで実行されるため、それは不可能であると述べました。ユーザーからバックグラウンドプロセスに渡すIDのリストをどのように保存していますか?順序を示す列のある一時テーブルにそれらを配置しないでください。

だからこれはどうですか:

  1. ユーザーインターフェイスビットが実行され、作成した新しいテーブルに値が挿入されます。ID、位置、ある種のジョブ番号識別子を挿入します)
  2. (すべてのIDではなく)ジョブ番号がバックグラウンドプロセスに渡されます。
  3. バックグラウンドプロセスは、手順1でテーブルから選択を行い、参加して、必要な他の情報を取得します。WHERE句でジョブ番号を使用し、position列で順序付けします。
  4. バックグラウンドプロセスが完了すると、ジョブ識別子に基づいてテーブルから削除されます。

1

結合を行うだけでデータが完全になるため、ハッキングや複雑な処理を行わない方法でデータを保管する必要があります。

たとえば、「最近再生した」トラックIDのリストがあります。SQLiteでは、次のようにします。

SELECT * FROM recently NATURAL JOIN tracks;

1
ああ、私は人生が
そんなに

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は、関連付けられたサブクエリが適切に機能するように少し調整する必要がありますが、基本的な原則は適切です。


注を参照してください。また、前述のように、クエリの例は非常に単純化されているため、サブクエリと組み合わせて1つのクエリにすることはできません。
ダリルハイン
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.