mysqlでのunionおよびorder by句の使用


123

mysqlクエリで、union with order byを使用したいと思います。私のサイトでの検索の距離に基づいたテーブルから、さまざまな基準に基づいてさまざまなタイプのレコードをフェッチしています。最初の選択クエリは、正確な場所検索に関連するデータを返します。2番目の選択クエリは、検索した場所から5 kms以内の距離に関連するデータを返します。3番目の選択クエリは、検索した場所から5〜15 km以内の距離に関連するデータを返します。

次に、ユニオンを使用してすべての結果をマージし、ページングのあるページに表示します。「正確な検索結果」「5 km以内の結果」などの適切な見出しの下

次に、idまたはadd_dateに基づいて結果を並べ替えます。しかし、クエリの最後にorder by句を追加すると(query1 union query 2 union query 3 order by add_date)、すべての結果を並べ替えます。しかし、私が望んでいるのは、それが各見出しの下でソートされることです。


各テーブルで並べ替えに使用するフィールドはどのタイプですか?
user151841 2010

回答:


221

これを行うには、各selectにrankという名前の疑似列を追加します。これは、他の基準で並べ替える前に、最初に並べ替えることができます。例:

select *
from (
    select 1 as Rank, id, add_date from Table 
    union all
    select 2 as Rank, id, add_date from Table where distance < 5
    union all
    select 3 as Rank, id, add_date from Table where distance between 5 and 15
) a
order by rank, id, add_date desc

9
なぜそこにa終わりがあるのですか?
Uday Hiwarale 2013

25
MySQLでは、派生テーブルにエイリアスが必要です。
RedFilter 2013

4
@RedFilter、よくわかりません。3つのテーブルすべてを選択してから?を実行するだけで、「すべてを派生テーブルとして選択」の要点は何order byですか?(「並べ替えたり、全体を制限するために、UNION結果を、個々の括弧SELECTのステートメントをして置くORDER BYか、LIMIT最後の後に」)。コードをi.stack.imgur.com/LpTMU.png
Pacerier

1
@Pacerierその構文がMySQLで機能する場合は、それを試してください。私の構文はもう少しクロスプラットフォームで、MySQLでは一般的に動作しません。ただし、より一般的なケースで機能するため、実際にはそれを好みます。たとえば、最後のUNIONクエリからの最初の10件の一致のみが必要な場合を検討します。とにかく、構文にフォールバックする必要があると思います。
RedFilter

1
@Pacerierでは、このように値を設定すると、上位の「select *」が「select id、add_date」になり、表示したくない場合は結果から「rank」が取り除かれることを考慮してください。
Dev Null

45

これを行うには、サブクエリを使用できます。

select * from (select values1 from table1 order by orderby1) as a
union all
select * from (select values2 from table2 order by orderby2) as b

1
Tnx、注文を分割するのに適しています。また、順序句が一般的であったならば、私たちはさまざまな構成を持つことができますが、我々は結果が(代わりに注文を分離する)分離たい: SELECT * FROM ( SELECT aaa AS Col, 1 AS Official FROM table1 UNION ALL SELECT bbb AS Col, 0 AS Official FROM table2 ) AS tbl ORDER BY Official, Col
アリックス

18
これは正しくないの使用ORDER BY個々のためSELECTのステートメントは、行が最終結果に表示される順序については何も意味しない
shmosel

あなたが正しい、受け入れられた答えも正しいものです。これをテストしたところ、たまたまうまくいきました。
rickythefox 2016年

shmosel(およびrickythefox)-union allは重複を削除しないため、個々のソートされた選択のソートを変更する理由はありません。これが過去にあなたのために働いた理由であり、それが将来あなたのために働く理由です。最終結果で混乱する順序は、UNION(DISTINCT)が行を効率的に組み合わせるために何らかのソートを必要とするためです。より具体的には、行を効率的に組み合わせるために並べ替えます。したがって、サブクエリを保持するためにunion allに依存できます。
Gerard ONeill 2017

2
これは古いMySQLバージョンではうまく機能していましたが、現在このアプローチは機能しません。SQL標準はサブクエリの順序を保持することを保証しないためです。
Andrei

28
(select add_date,col2 from table_name) 
  union 
(select add_date,col2 from table_name) 
  union 
(select add_date,col2 from table_name) 

order by add_date

これは機能しましたが、奇妙なことに、1つ変更する必要がありました。注文元のフィールドに共有エイリアスを指定する必要がありました。それ以外にも働いた、ありがとう!
HoldOffHunger 2016

9

ユニオンクエリORDER BYに含めることができるマスター句はIIRCのみです。これを行うには、より大きなクエリを構成する各クエリUNIONで、UNIONの並べ替えに使用する1つのフィールドとなるフィールドを追加しますORDER BY

たとえば、次のようなものがあるかもしれません

SELECT field1, field2, '1' AS union_sort
UNION SELECT field1, field2, '2' AS union_sort
UNION SELECT field1, field2, '3' AS union_sort
ORDER BY union_sort

そのunion_sortフィールドは、ソートしたいものであれば何でもかまいません。この例では、たまたま最初のテーブルの結果を最初に、2番目のテーブルを2番目にというように配置しています。


9

ユニオンは、ソートやマージを行わずにレコードセットにレコードを追加する方法です(ユニオンとは対照的です)。

だから例えば:

select * from (
    select col1, col2
    from table a
    <....>
    order by col3
    limit by 200
) a
union all
select * from (
    select cola, colb
    from table b
    <....>
    order by colb
    limit by 300
) b

これにより、個々のクエリが明確になり、各クエリの異なるパラメーターで並べ替えることができます。ただし、選択した回答の方法を使用すると、並べ替えを概念化しているため、複雑さとデータの関連性によっては明確になる場合があります。また、疑似列をクエリプログラムに返して、並べ替えや整理ができるコンテキストを持たせることもできます。

ただし、この方法には、余分な変数を導入せずに高速で、ソートを含む各クエリを簡単に分離できるという利点があります。制限を追加する機能は、単なる追加のボーナスです。

そしてもちろん、ユニオンをすべてユニオンに変えて、クエリ全体のソートを追加するのも自由です。または、人工的なIDを追加します。この場合、この方法を使用すると、各クエリのさまざまなパラメーターで簡単に並べ替えることができますが、それ以外は受け入れられた回答と同じです。


4

私はこれを結合と結合で動作させました。

(SELECT 
   table1.column1,
   table1.column2,
   foo1.column4
 FROM table1, table2, foo1, table5
 WHERE table5.somerecord = table1.column1
 ORDER BY table1.column1 ASC, table1.column2 DESC
)

UNION

(SELECT
    ... Another complex query as above
)

ORDER BY column1 DESC, column2 ASC

3

mysqlとORDER BY組み合わせて使用​​されるサブクエリ内で句を使用すると、句UNIONが最適化されORDER BYます。

これは、デフォルトではa UNIONが順序付けられていないリストを返すため、ORDER BYは何もしないためです。

最適化はドキュメントで言及されて言っています:

ORDER BYまたはLIMITを個々のSELECTに適用するには、SELECTを囲む括弧内に句を配置します。

(SELECT a FROM t1 WHERE a=10 AND B=1 ORDER BY a LIMIT 10) UNION
(SELECT a FROM t2 WHERE a=11 AND B=2 ORDER BY a LIMIT 10);

ただし、個々のSELECTステートメントにORDER BYを使用しても、UNIONはデフォルトで順序付けされていない行のセットを生成するため、最終結果に行が表示される順序については何も意味しません。したがって、このコンテキストでのORDER BYの使用は通常LIMITと組み合わせて使用​​されるため、SELECTで取得する選択された行のサブセットを決定するために使用されます。最終的なUNIONの結果。SELECTでORDER BYがLIMITなしで表示される場合、それはとにかく効果がないため、最適化されて削除されます。

これの最後の文は効果があるはずなので、少し誤解を招きます。この最適化により、サブクエリ内で順序付けする必要がある状況で問題が発生します。

MySQLにこの最適化を行わせないようにするには、次のようにLIMIT句を追加します。

(SELECT 1 AS rank, id, add_date FROM my_table WHERE distance < 5 ORDER BY add_date LIMIT 9999999999)
UNION ALL
(SELECT 2 AS rank, id, add_date FROM my_table WHERE distance BETWEEN 5 AND 15 ORDER BY rank LIMIT 9999999999)
UNION ALL
(SELECT 3 AS rank, id, add_date from my_table WHERE distance BETWEEN 5 and 15 ORDER BY id LIMIT 9999999999)

LIMITは、OFFSETページネーションなどを実行する場合にクエリ全体にを追加できることを意味します。

これにより、ORDER BYユニオンごとに異なる列を使用できるという追加の利点も得られます。


0

試してください:

SELECT result.* 
FROM (
 [QUERY 1]
 UNION
 [QUERY 2]
) result
ORDER BY result.id

ここで、[QUERY 1]と[QUERY 2]は、マージする2つのクエリです。


0

これは、結果セット全体をソートしているため、ユニオンのすべての部分を個別にソートする必要があるか、ORDER BY(Something ie。subquery distance)THEN(something ie row id)句を使用できるためです


0

のように結合する前に、各クエリに順序を追加してみました

(select * from table where distance=0 order by add_date) 
union 
(select * from table where distance>0 and distance<=5 order by add_date)

しかし、それはうまくいかなかったようです。実際には、各選択からの行内の順序付けは行いませんでした。

私はあなたが外側で順序を維持し、where句の列を次のような順序で追加する必要があると思います

(select * from table where distance=0) 
union 
(select * from table where distance>0 and distance<=5) 
order by distance, add_date

範囲でグループ化したいので、これは少しトリッキーかもしれませんが、私はそれができるはずだと思います。


以下のuser151841 union_sortのアイデアは、グループ化を処理する良い方法です
Mike C
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.