Cách xác định thứ tự tùy chỉnh theo thứ tự trong myQuery


142

Trong MySQL làm thế nào để tôi xác định một thứ tự sắp xếp tùy chỉnh.

Để cố gắng giải thích những gì tôi muốn xem xét bảng này:

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

Ở đây tôi muốn trả về tất cả các hàng được sắp xếp theo Ngôn ngữ và ID tăng dần để Language = ENU xuất hiện trước, sau đó là JPN và cuối cùng là DAN.

Kết quả sẽ là: a, d, b, e, c, f, v.v.

Điều này thậm chí có thể?

Câu trả lời:


274

MySQL có một chức năng tiện dụng được gọi FIELD()là tuyệt vời cho các nhiệm vụ như thế này.

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

Lưu ý, tuy nhiên,

  1. Nó làm cho SQL của bạn ít di động hơn, vì các DBMS khác có thể không có chức năng như vậy

  2. Khi danh sách ngôn ngữ của bạn (hoặc các giá trị khác để sắp xếp theo) dài hơn nhiều, tốt hơn là nên có một bảng riêng với cột sắp xếp cho chúng và nối nó với các truy vấn của bạn để đặt hàng.


3
Cảm ơn điều này là hoàn hảo cho tình huống của tôi khi tôi chỉ phải đặt hàng theo hai giá trị (ngôn ngữ chính, ví dụ JPN và ngôn ngữ dự phòng, ví dụ ENU).
Muleskinner

4
Người đàn ông bạn vừa cứu tôi viết lại trong magento :)
Erik Simonic 6/2/2015

1
Nếu bạn có GROUP BYtrước đây thì sao? Ví dụ, giá trị đầu tiên tôi muốn, xuất hiện ở cuối?
Pathros

Đặt truy vấn với GROUP BYtruy vấn con và đặt nó trong truy vấn bên ngoài
Mchl

1
Làm việc như một cơ duyên :)
Brane

53

Nếu đó là những chỉ có ba giá trị, sau đó bạn có thể sử dụng một CASEbiểu hiện :

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

(Nếu có thể có các giá trị khác, thì bạn có thể muốn thêm một số logic bổ sung để giữ cho thứ tự nhất quán; ví dụ: bạn có thể thêm ELSE 4vào CASEbiểu thức đó và sau đó tự Languageđặt hàng làm tiêu chí đặt hàng thứ ba:

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

)


1
Và nếu có nhiều giá trị Ngôn ngữ, bạn có thể có một bảng riêng lưu trữ từng Ngôn ngữ cộng với một cột thứ tự sắp xếp và liên kết đến đó
kaj

1
Điều này sẽ đặt hàng trước ID, dẫn đến a, b, c, d, e, f
piotrm

Cảm ơn điều này hoạt động hoàn hảo - cũng như câu trả lời của Mchl mà tôi đã chấp nhận vì nó trông đơn giản hơn
Muleskinner

19

Bạn có một vài lựa chọn tùy ý, đầu tiên là thay đổi Ngôn ngữ thành ENUM (giả sử điều này là có thể và bạn chỉ mong đợi một vài biến thể)

Nếu bạn chỉ định nó như ENUM('ENU','JPN','DAN')sau đó ORDER Language ASCsẽ đặt hàng theo thứ tự bạn chỉ định.

Thứ hai sẽ liên quan đến một trường hợp ở đâu đó, tức là

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

Hiệu suất thông minh, phương pháp ENUM sẽ trả về kết quả nhanh hơn, nhưng sẽ rắc rối hơn nếu bạn cần thêm nhiều ngôn ngữ. Tùy chọn thứ ba sẽ là thêm bảng chuẩn hóa cho các Ngôn ngữ tuy nhiên có thể là quá mức cần thiết trong trường hợp này.


Bạn gõ chính xác ở đâu ENUM('ENU','JPN','DAN')?
Pathros

1
@pathros trong định nghĩa bảng, bạn chỉ định nó là ENUM thay vì VARCHAR, v.v. MySQL bên trong lưu trữ các tùy chọn ENUM theo một thứ tự cụ thể và lập chỉ mục cho chúng, vì vậy khi đặt hàng theo cột ENUM cụ thể, nó sẽ sử dụng chỉ mục nội bộ đó thay vì các giá trị chuỗi (trừ khi CAST () được sử dụng để đưa nó trở lại VARCHAR)
Simon tại Cổng thông tin trường học của tôi

Không nên END DESC,END CASE DESC,?
Istiaque Ahmed

Không. Không phải tất cả CASEnhu cầu END CASE, nó phụ thuộc vào bối cảnh. CASEtrong PROCEDURE yêu cầu END CASE( dev.mysql.com/doc/refman/5.5/en/case.html ) tuy nhiên CASEtrong CHỌN không yêu cầu END CASE, chỉ đơn giản END( dev.mysql.com/doc/refman/5.7/en/iêu ) - trong này bối cảnh đó là một chức năng dòng điều khiển.
Simon tại Cổng thông tin trường học của tôi

1

Đối với khung Yii2, chúng tôi sẽ đạt được bằng cách sau

Project::find()
->orderBy([new Expression('FIELD(pid_is_t_m,2,0,1)'),'task_last_work'=> SORT_ASC])
->all();
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.