Menggunakan union dan order by clause di mysql


123

Saya ingin menggunakan order by with union dalam kueri mysql. Saya mengambil jenis rekaman yang berbeda berdasarkan kriteria yang berbeda dari tabel berdasarkan jarak untuk penelusuran di situs saya. Kueri pemilihan pertama mengembalikan data yang terkait dengan pencarian tempat yang tepat. Kueri pemilihan ke-2 mengembalikan data yang terkait dengan jarak dalam 5 km dari tempat yang dicari. Kueri pemilihan ke-3 mengembalikan data yang terkait dengan jarak dalam 5-15 km dari tempat yang dicari.

Kemudian saya menggunakan union untuk menggabungkan semua hasil dan ditampilkan di halaman dengan paging. Di bawah judul yang sesuai sebagai 'Hasil pencarian tepat' , 'Hasil dalam 5 km', dll

Sekarang saya ingin mengurutkan hasil berdasarkan id atau add_date. Tetapi ketika saya menambahkan pesanan dengan klausa di akhir kueri saya (kueri1 permintaan serikat 2 permintaan serikat 3 pesanan oleh add_date). Itu menyortir semua hasil. Tapi yang saya inginkan adalah itu harus diurutkan di bawah setiap judul.


Apa jenis bidang yang ingin Anda sortir di setiap tabel?
pengguna151841

Jawaban:


221

Anda dapat melakukan ini dengan menambahkan pseudo-kolom bernama rank ke setiap pilihan, yang dapat Anda urutkan terlebih dahulu, sebelum mengurutkan berdasarkan kriteria Anda yang lain, misalnya:

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
Mengapa ada adan akhirnya?
Uday Hiwarale

25
MySQL mengharuskan tabel turunan memiliki alias.
RedFilter

4
@RedFilter, saya tidak begitu mengerti. Apa inti dari "pilih semua sebagai tabel turunan" ketika kita cukup memilih ketiga tabel lalu melakukan order by? ( "untuk mengurutkan atau membatasi keseluruhan UNIONhasil, tanda kurung SELECTpernyataan individu dan tempatkan ORDER BYatau LIMITsetelah yang terakhir" ). Bandingkan kode Anda dengan i.stack.imgur.com/LpTMU.png
Pacerier

1
@Pacerier Jika sintaks itu bekerja dengan MySQL, lakukanlah! Sintaks saya sedikit lebih lintas platform, saya biasanya tidak bekerja dengan MySQL. Saya sebenarnya lebih suka, karena ini berfungsi dalam kasus yang lebih umum, misalnya, pertimbangkan ketika Anda hanya menginginkan sepuluh kecocokan pertama dari kueri UNION terakhir - saya pikir Anda tetap harus kembali ke sintaks saya.
RedFilter

1
@Pacerier, pertimbangkan juga bahwa nilai dengan cara ini memungkinkan "pilih *" teratas itu menjadi "pilih id, add_date" dan hapus "peringkat" dari hasil jika Anda tidak ingin melihatnya.
Dev Null

45

Anda dapat menggunakan subkueri untuk melakukan ini:

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, Bagus untuk memisahkan pesanan. Juga kita dapat memiliki pengaturan yang berbeda jika klausa pesanan biasa tetapi kita ingin hasilnya dipisahkan (bukan memisahkan pesanan): 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
Alix

18
Ini tidak benar : penggunaan ORDER BYuntuk SELECTpernyataan individu tidak menyiratkan apa pun tentang urutan kemunculan baris pada hasil akhir
shmosel

Anda benar, jawaban yang diterima juga benar. Ini kebetulan bekerja dengan baik saat saya mengujinya.
rickythefox

shmosel (dan rickythefox) - penyatuan semua tidak menghapus duplikat, sehingga tidak memiliki alasan untuk mengubah jenis pilihan yang diurutkan secara individu. Inilah mengapa ini berhasil untuk Anda di masa lalu, dan mengapa ini akan berhasil untuk Anda di masa depan. Urutan menjadi kacau pada hasil akhir karena UNION (DISTINCT) membutuhkan semacam penyortiran untuk menggabungkan baris secara efisien. Atau lebih spesifiknya, urutkan karena ini menggabungkan baris secara efisien. Jadi, Anda dapat bergantung pada serikat semua untuk mempertahankan subkueri Anda.
Gerard ONeill

2
Ini berfungsi dengan baik untuk versi MySQL yang lebih lama, sekarang pendekatan ini TIDAK akan berfungsi. Karena standar SQL tidak menjamin untuk mempertahankan urutan subquery.
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

Ini berhasil, tetapi anehnya saya perlu mengubah satu hal: Saya perlu memberikan alias bersama ke bidang yang dipesan oleh. Bekerja selain itu, terima kasih!
HoldOffHunger

9

Kueri gabungan hanya dapat memiliki satu ORDER BYklausa master , IIRC. Untuk mendapatkan ini, dalam setiap kueri yang membuat kueri yang lebih besar UNION, tambahkan bidang yang akan menjadi satu bidang yang Anda urutkan untuk UNIONitu ORDER BY.

Misalnya, Anda mungkin memiliki sesuatu seperti

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

Itu union_sortlapangan dapat apa pun yang Anda mungkin ingin sortir. Dalam contoh ini, ini kebetulan menempatkan hasil dari tabel pertama pertama, tabel kedua kedua, dll.


9

Jangan lupa, penyatuan semua adalah cara untuk menambahkan catatan ke kumpulan catatan tanpa penyortiran atau penggabungan (sebagai lawan dari penyatuan).

Jadi contohnya:

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

Itu membuat kueri individu lebih jelas dan memungkinkan Anda untuk mengurutkan berdasarkan parameter yang berbeda di setiap kueri. Namun dengan menggunakan cara jawaban yang dipilih, itu mungkin menjadi lebih jelas tergantung pada kompleksitas dan seberapa terkait datanya karena Anda membuat konsep pengurutan. Ini juga memungkinkan Anda untuk mengembalikan kolom buatan ke program kueri sehingga memiliki konteks yang dapat diurutkan atau diatur.

Tetapi cara ini memiliki keuntungan karena cepat, tidak memasukkan variabel tambahan, dan membuatnya mudah untuk memisahkan setiap kueri termasuk jenisnya. Kemampuan untuk menambahkan batas hanyalah bonus tambahan.

Dan tentu saja jangan ragu untuk mengubah gabungan semua menjadi satu dan menambahkan semacam untuk seluruh kueri. Atau tambahkan id buatan, dalam hal ini cara ini memudahkan pengurutan berdasarkan parameter berbeda di setiap kueri, tetapi sebaliknya sama dengan jawaban yang diterima.


4

Saya mendapatkan ini bekerja di join plus union.

(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

Saat Anda menggunakan ORDER BYklausa di dalam sub kueri yang digunakan bersama dengan UNIONmysql akan mengoptimalkan ORDER BYklausa tersebut.

Ini karena secara default a UNIONmengembalikan daftar tidak berurutan sehingga oleh karena itu an ORDER BYtidak akan melakukan apa-apa.

Pengoptimalan disebutkan di dokumen dan mengatakan:

Untuk menerapkan ORDER BY atau LIMIT ke SELECT individu, tempatkan klausa di dalam tanda kurung yang mengapit 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);

Namun, penggunaan ORDER BY untuk pernyataan SELECT individual tidak menyiratkan apa pun tentang urutan kemunculan baris di hasil akhir karena UNION secara default menghasilkan kumpulan baris yang tidak berurutan. Oleh karena itu, penggunaan ORDER BY dalam konteks ini biasanya terkait dengan LIMIT, sehingga digunakan untuk menentukan subset dari baris yang dipilih untuk diambil untuk SELECT, meskipun itu tidak selalu mempengaruhi urutan baris tersebut di hasil UNION akhir. Jika ORDER BY muncul tanpa LIMIT dalam SELECT, itu dioptimalkan karena itu tidak akan berpengaruh.

Kalimat terakhir ini agak menyesatkan karena seharusnya memiliki efek. Pengoptimalan ini menyebabkan masalah saat Anda berada dalam situasi di mana Anda perlu memesan dalam subkueri.

Untuk memaksa MySQL agar tidak melakukan pengoptimalan ini, Anda dapat menambahkan klausa LIMIT seperti ini:

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

Tinggi LIMITberarti Anda dapat menambahkan OFFSETkueri pada keseluruhan jika Anda ingin melakukan sesuatu seperti penomoran halaman.

Ini juga memberi Anda manfaat tambahan karena dapat ORDER BYmenggunakan kolom yang berbeda untuk setiap serikat pekerja.


0

Mencoba:

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

Di mana [QUERY 1] dan [QUERY 2] adalah dua kueri Anda yang ingin Anda gabungkan.


0

Ini karena Anda sedang mengurutkan seluruh kumpulan hasil, Anda harus mengurutkan, setiap bagian dari gabungan secara terpisah, atau Anda dapat menggunakan ORDER BY (Sesuatu yaitu jarak subkueri) THEN (sesuatu yaitu baris id) klausa


0

Saya mencoba menambahkan urutan untuk setiap pertanyaan sebelum penyatuan seperti

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

tapi sepertinya tidak berhasil. Itu tidak benar-benar melakukan pengurutan dalam baris dari setiap pilihan.

Saya pikir Anda perlu menjaga urutan di luar dan menambahkan kolom di klausa where ke urutan oleh, seperti

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

Ini mungkin sedikit rumit, karena Anda ingin mengelompokkan berdasarkan rentang, tetapi saya pikir itu harus bisa dilakukan.


user151841 ide union_sort di bawah ini akan menjadi cara yang bagus untuk menangani pengelompokan
Mike C
Dengan menggunakan situs kami, Anda mengakui telah membaca dan memahami Kebijakan Cookie dan Kebijakan Privasi kami.
Licensed under cc by-sa 3.0 with attribution required.