MySQL'de özel bir ORDER BY siparişi nasıl tanımlanır


143

MySQL'de nasıl özel bir sıralama düzeni tanımlayabilirim?

Ne istediğimi açıklamaya çalışmak için bu tabloyu düşünün:

ID  Language    Text
0   ENU         a
0   JPN         b
0   DAN         c       
1   ENU         d
1   JPN         e
1   DAN         f
2   etc...

burada Dil = ENU önce gelir, sonra JPN ve son olarak DAN böylece Dil ve artan ID göre sıralanmış tüm satırları döndürmek istiyorum.

Sonuç şöyle olmalıdır: a, d, b, e, c, f vb.

Bu mümkün mü?

Yanıtlar:


276

MySQL, FIELD()bu gibi görevler için mükemmel olan kullanışlı bir işleve sahiptir .

ORDER BY FIELD(Language,'ENU','JPN','DAN'), ID

Ancak,

  1. Diğer DBMS'ler böyle bir işleve sahip olmayabileceğinden SQL'inizi daha az taşınabilir hale getirir

  2. Dil listeniz (veya sıralamak için diğer değerler) çok uzadığında, onlar için sortorder sütunu olan ayrı bir tabloya sahip olmak ve sipariş için sorgularınıza katılmak daha iyidir.


3
Teşekkürler, bu sadece iki değerle sipariş etmem gereken durumum için mükemmel (birincil dil, örneğin JPN ve yedek bir dil, örneğin ENU).
Muleskinner

4
Adam az önce beni
kırmızı

1
Daha GROUP BYönce sahipseniz ? Örneğin, istediğim ilk değer sonunda görünüyor mu?
Pathros

Sorguyu GROUP BYbir alt sorguya koyun ve dış sorguya sipariş edin
Mchl

1
Bir cazibe gibi çalış :)
Brane

53

Bunlar yalnızca üç değerse, bir CASEifade kullanabilirsiniz :

ORDER BY `ID`,
         CASE `Language`
         WHEN 'ENU' THEN 1
         WHEN 'JPN' THEN 2
         WHEN 'DAN' THEN 3
         END

(Başka değerler olabilirse, sıralamayı tutarlı tutmak için ekstra bir mantık eklemek isteyebilirsiniz; örneğin, ELSE 4bu CASEifadeye ekleyebilir ve daha sonra Languageüçüncü sipariş kriteri olarak kendi başına sipariş verebilirsiniz :

ORDER BY `ID`,
         CASE `Language`
         WHEN 'ENU' THEN 1
         WHEN 'JPN' THEN 2
         WHEN 'DAN' THEN 3
         ELSE 4
         END,
         `Language`

)


1
Ve eğer çok sayıda Dil değeri varsa, her bir Dili ve bir sıralama düzeni sütununu saklayan ayrı bir tabloya sahip olabilirsiniz ve buna bağlantı kurabilirsiniz
kaj

1
Bu önce kimliğe göre sıralanır, sonuç a, b, c, d, e, f
piotrm

Teşekkürler bu mükemmel çalışıyor - daha basit göründüğü gibi kabul Mchl cevap gibi
Muleskinner

19

Elinizde birkaç seçenek var, birincisi Dili ENUM olarak değiştirmek (bunun mümkün olduğunu varsayarsak ve sadece birkaç varyasyon beklersiniz)

Eğer belirtirseniz olarak ENUM('ENU','JPN','DAN')o ORDER Language ASCbelirttiğiniz sırayla sipariş olacaktır.

İkincisi bir yerde bir dava içerecektir, yani

SELECT * FROM table
ORDER BY CASE Language
    WHEN 'ENU' THEN 3
    WHEN 'JPN' THEN 2
    WHEN 'DAN' THEN 1
    ELSE 0
END DESC, ID ASC

Performans açısından ENUM yöntemi daha hızlı sonuç verir, ancak daha fazla dil eklemeniz gerekirse daha fazla güçlük çekersiniz. Üçüncü bir seçenek, Diller için normalleştirme tablosu eklemek olabilir, ancak bu örnekte aşırıya kaçabilir.


Tam olarak nereye yazıyorsunuz ENUM('ENU','JPN','DAN')?
Pathros

1
@pathros tablo tanımında, VARCHAR vb. yerine ENUM olarak belirtirsiniz. Dahili olarak MySQL, ENUM seçeneklerini belirli bir sırayla depolar ve endeksler ve böylece bir ENUM sütunu ile sipariş verirken, dize değerleri (CAST () bir VARCHAR'a geri döndürmek için kullanılmazsa)
Simon My School Portal'da

Gerekmiyor END DESC,olmak END CASE DESC,?
Istiaque Ahmed

Hayır! Her şeye CASEihtiyaç duymaz END CASE, bağlama bağlıdır. CASEPROCEDURE içinde gerektirir END CASE( dev.mysql.com/doc/refman/5.5/en/case.html ), ancak CASESELECT içinde gerektirmez END CASE, basitçe END( dev.mysql.com/doc/refman/5.7/en/… ) - bu bağlam bir kontrol akış fonksiyonudur.
Simon My School Portal'da

1

Yii2 çerçevesi için kabin şu şekilde elde ediyoruz

Project::find()
->orderBy([new Expression('FIELD(pid_is_t_m,2,0,1)'),'task_last_work'=> SORT_ASC])
->all();
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.