sql Belirli bir sırayla birden fazla değere göre SİPARİŞ?


102

Tamam, indekslenmiş bir anahtar ve indekslenmemiş alan içeren bir tablom var. Belirli bir değere sahip tüm kayıtları bulmam ve satırı döndürmem gerekiyor. Birden fazla değere göre sipariş verip veremeyeceğimi bilmek istiyorum.

Misal:

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

sözde: sonuçların bu şekilde sıralanmasını ister, 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'

Böylece sonuçlar şöyle olacaktır:

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

Sözdizimi geçerlidir ancak sorguyu yürüttüğümde, 1 kayıtla sınırlasam bile hiçbir zaman sonuç döndürmez. Bunu yapmanın başka bir yolu var mı?

X_field'ı test sonuçları olarak düşünün ve koşula giren tüm kayıtları doğrulamam gerekiyor. Test sonuçlarını başarısız değerler, geçilen değerlere göre sıralamak istedim. Böylece, önce başarısız olan değerleri ve ardından ORDER BY kullanarak geçirilen değerleri doğrulayabilirim.

Yapamadığım şey:

  • GROUP BY, belirli kayıt değerlerini döndürmem gerektiği için
  • NEREDE x_field IN ('f', 'p', 'i', 'a'), birkaç doğrulama testi için bir sorgu kullanmaya çalıştığım için tüm değerlere ihtiyacım var. Ve x_field değerleri DESC / ASC düzeninde değil

Bu soruyu yazdıktan sonra, bunu yeniden düşünmem gerektiğini düşünmeye başladım, LOL!


Belki bunun yerine bir sendika? Sonuçların döndürülmesini istediğiniz sırada ayrı sorgular oluşturun, sonra bu sorgular arasında bir birleşim mi var?
kinakuta

Yanıtlar:


193
...
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

30

"VALUES ('f', 1), ('p', 2), ('a', 3), ('i', 4)" ile LEFT JOIN kullanabilir ve ikinci sütunu sıranızdaki kullanabilirsiniz - ifadeyle. Postgres, çok fazla değeriniz varsa, büyük bir CASE'den çok daha hızlı olacak bir Hash Join kullanacaktır. Ve otomatik olarak oluşturmak daha kolaydır.

Bu sipariş bilgileri sabitse, kendi tablosuna sahip olmalıdır.


6
Bu, açık ara en zarif çözümdür!
jnns

28

Deneyin:

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

Doğru yoldaydınız, ancak x_field'ı yalnızca F değerine koyarak, diğer 3'ü sabitler olarak kabul edildi ve veri kümesindeki hiçbir şeyle karşılaştırılmadı.


Postgres örtük boole'yi destekliyor mu? Öyleyse, boole nasıl sıralanır?
gbn

Bu çözümü beğendim ama bir daha geri dönmedi.
Phill Pafford

@gbn, Evet ve yanlış <doğru. Bunun işe yaramasını beklerdim.
Andrew Lazarus

7
Evet, Postgres'te etkinlik olarak çalışıyor. Bu çözüme dikkat edin, sonuçların ters sırada sıralanmasıdır. Bu yüzden alanları ters sıraya koymanız gerekir: ORDER BY x_field = 'A', x_field = 'I', x_field = 'P', x_field = 'F',
igo

16

caseKodları sıralanabilecek sayılara çevirmek için bir anahtar kullanın :

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

12

Bunun için çok daha temiz bir çözüm buldum:

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

Not: array_position için Postgres v9.5 veya üstü gerekir.


1
Array_position () 'un yalnızca Postgres v9.5'ten itibaren mevcut olduğuna dikkat etmek önemlidir, afaik.
bigsee

teşekkürler, bunu CASE yöntemlerine çok tercih ettik. Tamsayılarla da çalışır; array_position(ARRAY[1, 0]::integer[], x_field)
Paul Watson

7

CASEVe ORDER BYönerileri tüm çalışmaları gerektiği, ancak farklı bir renkte bir atı önermek için gidiyorum. Yalnızca makul sayıda değer olduğunu x_fieldve bunların ne olduğunu zaten bildiğinizi varsayarak, F, P, A ve I değerleri olarak (artı diğer olası değerler geçerliyse) numaralandırılmış bir tür oluşturun . Numaralandırmalar, CREATEifadelerinin ima ettiği sıraya göre sıralanır . Ayrıca, anlamlı değer adlarını kullanabilirsiniz - gerçek uygulamanız muhtemelen yapar ve onları gizlilik için maskelemişsinizdir - sadece sıra konumu saklandığı için alan israf etmeden.


1

Seçili bir sütuna veya diğer ifadelere göre sıralayabilirsiniz.

Burada bir örnek, bir durum ifadesinin sonucuna göre nasıl sıralanacağı:

  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

Sonuç, "IsGen = 0" satırları ile başlayan ve ardından "IsGen = 1" satırları ve diğer tüm satırlar ile biten bir Liste olacaktır.

Sonunda daha fazla sipariş parametresi ekleyebilirsiniz:

  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

Bu kod parçacığı sorunu çözebilirken soruyu neden veya nasıl yanıtladığını açıklamaz. Lütfen kodunuz için bir açıklamaya yer gerçekten Yayınınızla kalitesini artırmak için yardımcı olarak,. Gelecekte okuyucular için soruyu yanıtlayacağınızı ve bu kişilerin kod önerinizin nedenlerini bilmeyebileceklerini unutmayın.
Samuel Philipp

0

CASE ile ORDER BY'da yeni olan biri için bu yararlı olabilir

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

0

Yorum yazmak için yeterli itibarım olmadığından, bunu yeni bir cevap olarak ekledim.

Maddeye göre sıraya artan veya azalan ekleyebilirsiniz.

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

bu da I birinci, P ikinci ve A'yı sonuncu ve F'yi sondan önce yapar.


0

@ bobflux'un cevabı harika. Önerilen yaklaşımı kullanan eksiksiz bir sorgu ekleyerek bunu genişletmek istiyorum.

select tt.id, tt.x_field
from target_table as tt
-- Here we join our target_table with order_table to specify custom ordering.
left join
    (values ('f', 1), ('p', 2), ('i', 3), ('a', 4)) as order_table (x_field, order_num)
    on order_table.x_field = tt.x_field
order by
    order_table.order_num, -- Here we order values by our custom order.
    tt.x_field;            -- Other values can be ordered alphabetically, for example.

İşte tam demo .


Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.