sql ORDER BY beberapa nilai dalam urutan tertentu?

99

Ok saya memiliki tabel dengan kunci yang diindeks dan bidang yang tidak diindeks. Saya perlu menemukan semua record dengan nilai tertentu dan mengembalikan barisnya. Saya ingin tahu apakah saya dapat memesan dengan beberapa nilai.

Contoh:

id     x_field
--     -----
123    a
124    a
125    a
126    b
127    f
128    b
129    a
130    x
131    x
132    b
133    p
134    p
135    i

semu: ingin hasil diurutkan seperti ini, where ORDER BY x_field = 'f', 'p', 'i', 'a'

SELECT *
FROM table
WHERE id NOT IN (126)
ORDER BY x_field 'f', 'p', 'i', 'a'

Jadi hasilnya adalah:

id     x_field
--     -----
127    f
133    p
134    p
135    i
123    a
124    a
125    a
129    a

Sintaksnya valid tetapi ketika saya menjalankan kueri, ia tidak pernah mengembalikan hasil apa pun, bahkan jika saya membatasinya menjadi 1 catatan. Apakah ada cara lain untuk melakukannya?

Pikirkan x_field sebagai hasil tes dan saya perlu memvalidasi semua catatan yang termasuk dalam kondisi tersebut. Saya ingin memesan hasil tes dengan nilai gagal, nilai lulus. Jadi saya bisa memvalidasi nilai yang gagal terlebih dahulu dan kemudian nilai yang diteruskan menggunakan ORDER BY.

Yang tidak bisa saya lakukan:

  • GROUP BY, karena saya perlu mengembalikan nilai record tertentu
  • DI MANA x_field IN ('f', 'p', 'i', 'a'), saya memerlukan semua nilai karena saya mencoba menggunakan satu kueri untuk beberapa uji validasi. Dan nilai x_field tidak dalam urutan DESC / ASC

Setelah menulis pertanyaan ini saya mulai berpikir bahwa saya perlu memikirkan kembali ini, LOL!

Phill Pafford
sumber
Mungkin serikat pekerja saja? Buat kueri terpisah dalam urutan yang Anda inginkan agar hasilnya dikembalikan, lalu lakukan penyatuan kueri tersebut?
kinakuta

Jawaban:

189
...
WHERE
   x_field IN ('f', 'p', 'i', 'a') ...
ORDER BY
   CASE x_field
      WHEN 'f' THEN 1
      WHEN 'p' THEN 2
      WHEN 'i' THEN 3
      WHEN 'a' THEN 4
      ELSE 5 --needed only is no IN clause above. eg when = 'b'
   END, id
gbn
sumber
29

Anda dapat menggunakan LEFT JOIN dengan "VALUES ('f', 1), ('p', 2), ('a', 3), ('i', 4)" dan menggunakan kolom kedua dalam urutan Anda -dengan ekspresi. Postgres akan menggunakan Hash Join yang akan jauh lebih cepat daripada CASE besar jika Anda memiliki banyak nilai. Dan lebih mudah untuk membuat otomatis.

Jika informasi pemesanan ini diperbaiki, maka itu harus memiliki tabelnya sendiri.

bobflux.dll
sumber
6
Sejauh ini, ini adalah solusi paling elegan!
jnns
28

Mencoba:

ORDER BY x_field='F', x_field='P', x_field='A', x_field='I'

Anda berada di jalur yang benar, tetapi dengan meletakkan x_field hanya pada nilai F, 3 lainnya diperlakukan sebagai konstanta dan tidak dibandingkan dengan apa pun dalam kumpulan data.

Marc B
sumber
Apakah Postgres mendukung boolean implisit? Jika ya, bagaimana boolean mengurutkan?
gbn
Saya menyukai solusi ini tetapi tidak mengembalikan apa pun lagi.
Phill Pafford
@gbn, Ya dan salah <benar. Saya berharap ini berhasil.
Andrew Lazarus
7
Ya, ini berfungsi acara di Postgres. Catatan untuk solusi ini adalah Anda mendapatkan hasil yang diurutkan dalam urutan terbalik. Jadi Anda harus meletakkan bidang dalam urutan terbalik: ORDER BY x_field = 'A', x_field = 'I', x_field = 'P', x_field = 'F',
igo
16

Gunakan casesakelar untuk menerjemahkan kode menjadi angka yang dapat diurutkan:

ORDER BY
  case x_field
  when 'f' then 1
  when 'p' then 2
  when 'i' then 3
  when 'a' then 4
  else 5
  end
Guffa
sumber
11

Saya menemukan solusi yang jauh lebih bersih untuk ini:

ORDER BY array_position(ARRAY['f', 'p', 'i', 'a']::varchar[], x_field)

Catatan: array_position membutuhkan Postgres v9.5 atau lebih tinggi.

reptil
sumber
1
Penting untuk dicatat bahwa array_position () hanya tersedia di Postgres v9.5 dan seterusnya, afaik.
lihat besar
terima kasih, ini lebih disukai daripada metode CASE. Bekerja dengan bilangan bulat juga; array_position(ARRAY[1, 0]::integer[], x_field)
Paul Watson
7

The CASEdan ORDER BYsaran semua harus bekerja, tapi aku akan menyarankan kuda warna yang berbeda. Dengan asumsi bahwa hanya ada sejumlah nilai yang masuk akal x_fielddan Anda sudah tahu apa itu, buat tipe enumerasi dengan F, P, A, dan I sebagai nilai (ditambah nilai lain yang mungkin berlaku). Enums akan mengurutkan dalam urutan yang tersirat oleh CREATEpernyataan mereka . Selain itu, Anda dapat menggunakan nama nilai yang berarti — aplikasi Anda yang sebenarnya mungkin melakukannya dan Anda baru saja menutupinya untuk kerahasiaan — tanpa membuang ruang, karena hanya posisi ordinal yang disimpan.

Andrew Lazarus
sumber
1

Anda dapat mengurutkan berdasarkan kolom yang dipilih atau ekspresi lain.

Berikut contoh cara memesan berdasarkan hasil pernyataan kasus:

  SELECT col1
       , col2
    FROM tbl_Bill
   WHERE col1 = 0
ORDER BY -- order by case-statement
    CASE WHEN tbl_Bill.IsGen = 0 THEN 0
         WHEN tbl_Bill.IsGen = 1 THEN 1
         ELSE 2 END

Hasilnya akan menjadi Daftar yang dimulai dengan baris "IsGen = 0", diikuti oleh baris "IsGen = 1" dan semua baris lainnya diakhiri.

Anda dapat menambahkan lebih banyak parameter pesanan di akhir:

  SELECT col1
       , col2
    FROM tbl_Bill
   WHERE col1 = 0
ORDER BY -- order by case-statement
    CASE WHEN tbl_Bill.IsGen = 0 THEN 0
         WHEN tbl_Bill.IsGen = 1 THEN 1
         ELSE 2 END,
         col1,
         col2
Kode
sumber
Meskipun cuplikan kode ini dapat menyelesaikan masalah, cuplikan kode ini tidak menjelaskan mengapa atau bagaimana menjawab pertanyaan tersebut. Harap sertakan penjelasan untuk kode Anda , karena itu sangat membantu meningkatkan kualitas posting Anda. Ingatlah bahwa Anda menjawab pertanyaan untuk pembaca di masa mendatang, dan orang-orang itu mungkin tidak tahu alasan saran kode Anda.
Samuel Philipp
0

Bagi seseorang yang baru mengenal ORDER BY dengan CASE ini semoga bermanfaat

ORDER BY 
    CASE WHEN GRADE = 'A' THEN 0
         WHEN GRADE = 'B' THEN 1
         ELSE 2 END
Akitha_MJ
sumber
-2

Anda dapat menggunakan posisi (teks dalam teks) secara berurutan untuk mengurutkan urutan

Mukesh Kulal
sumber