Sử dụng mệnh đề union và order by trong mysql


123

Tôi muốn sử dụng order by with union trong truy vấn mysql. Tôi đang tìm nạp các loại bản ghi khác nhau dựa trên các tiêu chí khác nhau từ một bảng dựa trên khoảng cách cho một tìm kiếm trên trang web của tôi. Truy vấn chọn đầu tiên trả về dữ liệu liên quan đến tìm kiếm địa điểm chính xác. Truy vấn chọn thứ 2 trả về dữ liệu liên quan đến khoảng cách trong vòng 5 km tính từ địa điểm được tìm kiếm. Truy vấn chọn thứ 3 trả về dữ liệu liên quan đến khoảng cách trong vòng 5-15 km từ địa điểm được tìm kiếm.

Sau đó, tôi sử dụng union để hợp nhất tất cả các kết quả và hiển thị trên một trang có phân trang. Dưới tiêu đề thích hợp như 'Kết quả tìm kiếm chính xác' , 'Kết quả trong vòng 5 km', v.v.

Bây giờ tôi muốn sắp xếp kết quả dựa trên id hoặc add_date. Nhưng khi tôi thêm thứ tự theo mệnh đề vào cuối truy vấn của mình (truy vấn 1 công đoàn 2 truy vấn công đoàn 3 thứ tự theo ngày thêm). Nó sắp xếp tất cả các kết quả. Nhưng điều tôi muốn là nó phải sắp xếp theo từng tiêu đề.


(Các) loại là / là (các) trường bạn muốn sắp xếp trong mỗi bảng?
dùng151841

Câu trả lời:


221

Bạn có thể làm điều này bằng cách thêm một cột giả có tên xếp hạng vào mỗi lựa chọn, mà bạn có thể sắp xếp theo thứ tự trước, trước khi sắp xếp theo các tiêu chí khác của bạn, ví dụ:

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
Tại sao có avà kết thúc?
Uday Hiwarale 23/1213

25
MySQL yêu cầu các bảng dẫn xuất phải có bí danh.
RedFilter

4
@RedFilter, tôi không hiểu lắm. Toàn bộ điểm của "chọn tất cả làm bảng dẫn xuất" là gì khi chúng ta có thể chỉ cần chọn tất cả 3 bảng sau đó thực hiện một order by? ( "để sắp xếp hoặc giới hạn toàn bộ UNIONkết quả, hãy đặt dấu ngoặc đơn cho từng SELECTcâu lệnh và đặt ORDER BYhoặc LIMITsau câu cuối cùng" ). So sánh mã của bạn với i.stack.imgur.com/LpTMU.png
Pacerier

1
@Pacerier Nếu cú ​​pháp đó hoạt động với MySQL, hãy tiếp tục! Cú pháp của tôi đa nền tảng hơn một chút, nói chung tôi không làm việc với MySQL. Tuy nhiên, tôi thực sự thích nó hơn, vì nó hoạt động trong các trường hợp tổng quát hơn, ví dụ, hãy cân nhắc khi bạn chỉ muốn mười kết quả phù hợp đầu tiên từ truy vấn UNION cuối cùng - Tôi nghĩ bạn sẽ phải quay lại cú pháp của tôi.
RedFilter

1
@Pacerier, cũng hãy xem xét rằng giá trị theo cách này cho phép "select *" hàng đầu đó thay vào đó là "select id, add_date" và loại bỏ "rank" ra khỏi kết quả nếu bạn không muốn nhìn thấy chúng.
Dev Null

45

Bạn có thể sử dụng các truy vấn con để thực hiện việc này:

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, Tốt một trong những đơn đặt hàng riêng biệt. Ngoài ra chúng tôi có thể có một sự sắp xếp khác nhau nếu mệnh đề trật tự đã được phổ biến nhưng chúng tôi muốn các kết quả tách ra (thay vì tách đơn đặt hàng): 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
Điều này không chính xác : việc sử dụng ORDER BYcho các SELECTcâu lệnh riêng lẻ không ngụ ý gì về thứ tự các hàng xuất hiện trong kết quả cuối cùng
shmosel

Bạn đúng, câu trả lời được chấp nhận cũng là câu đúng. Điều này chỉ xảy ra hoạt động tốt khi tôi thử nghiệm nó.
rickythefox

shmosel (và rickythefox) - union tất cả không loại bỏ các bản sao, và vì vậy không có lý do gì để thay đổi loại lựa chọn được sắp xếp của cá nhân bạn. Đây là lý do tại sao nó có hiệu quả với bạn trong quá khứ và tại sao nó sẽ hiệu quả với bạn trong tương lai. Thứ tự bị lộn xộn trong kết quả cuối cùng là do UNION (DISTINCT) cần một số loại sắp xếp để kết hợp các hàng một cách hiệu quả. Hay cụ thể hơn là sắp xếp vì nó kết hợp các hàng một cách hiệu quả. Vì vậy, bạn có thể phụ thuộc vào liên minh tất cả để duy trì các truy vấn con của bạn.
Gerard ONeill

2
Điều này đã hoạt động tốt cho các phiên bản MySQL cũ hơn, bây giờ cách tiếp cận này sẽ KHÔNG hoạt động. Bởi vì tiêu chuẩn SQL không đảm bảo duy trì thứ tự của truy vấn con.
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

Điều này đã hiệu quả, nhưng kỳ lạ là tôi cần phải thay đổi một điều: tôi cần phải cung cấp một bí danh chung cho lĩnh vực đang đặt hàng. Làm việc bên cạnh đó, cảm ơn!
HoldOffHunger

9

Một truy vấn liên hợp chỉ có thể có một ORDER BYmệnh đề chính, IIRC. Để có được điều này, trong mỗi truy vấn tạo thành UNIONtruy vấn lớn hơn , hãy thêm một trường sẽ là một trường mà bạn sắp xếp cho UNION's ORDER BY.

Ví dụ, bạn có thể có một cái gì đó như

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

Trường đó union_sortcó thể là bất kỳ thứ gì bạn có thể muốn sắp xếp theo. Trong ví dụ này, nó chỉ xảy ra khi đặt kết quả từ bảng đầu tiên trước tiên, bảng thứ hai thứ hai, v.v.


9

Đừng quên, liên hợp tất cả là một cách để thêm các bản ghi vào một tập hợp bản ghi mà không cần sắp xếp hoặc hợp nhất (trái ngược với liên hợp).

Ví dụ:

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

Nó giữ cho các truy vấn riêng lẻ rõ ràng hơn và cho phép bạn sắp xếp theo các tham số khác nhau trong mỗi truy vấn. Tuy nhiên, bằng cách sử dụng cách của câu trả lời đã chọn, nó có thể trở nên rõ ràng hơn tùy thuộc vào độ phức tạp và mức độ liên quan của dữ liệu bởi vì bạn đang khái niệm hóa loại sắp xếp. Nó cũng cho phép bạn trả lại cột nhân tạo cho chương trình truy vấn để nó có ngữ cảnh mà nó có thể sắp xếp hoặc tổ chức.

Nhưng cách này có ưu điểm là nhanh chóng, không đưa thêm biến và dễ dàng tách từng truy vấn bao gồm cả sắp xếp. Khả năng thêm giới hạn chỉ đơn giản là một phần thưởng thêm.

Và tất nhiên, hãy thoải mái biến tất cả liên kết thành một liên hợp và thêm một loại cho toàn bộ truy vấn. Hoặc thêm id nhân tạo, trong trường hợp này, cách này giúp bạn dễ dàng sắp xếp theo các tham số khác nhau trong mỗi truy vấn, nhưng nếu không thì nó giống với câu trả lời được chấp nhận.


4

Tôi nhận được điều này làm việc trên một công đoàn cộng với tham gia.

(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

Khi bạn sử dụng một ORDER BYmệnh đề bên trong một truy vấn phụ được sử dụng cùng với một UNIONmysql sẽ tối ưu hóa ORDER BYmệnh đề đó.

Điều này là do theo mặc định, một UNIONtrả về một danh sách không có thứ tự, do đó, một ORDER BYsẽ không làm gì cả.

Tối ưu hóa được đề cập trong tài liệu và cho biết:

Để áp dụng ORDER BY hoặc LIMIT cho một SELECT riêng lẻ, hãy đặt mệnh đề bên trong dấu ngoặc đơn bao quanh 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);

Tuy nhiên, việc sử dụng ORDER BY cho các câu lệnh SELECT riêng lẻ không ngụ ý gì về thứ tự các hàng xuất hiện trong kết quả cuối cùng vì UNION theo mặc định tạo ra một tập hợp các hàng không có thứ tự. Do đó, việc sử dụng ORDER BY trong ngữ cảnh này thường kết hợp với LIMIT, để nó được sử dụng để xác định tập hợp con của các hàng đã chọn để truy xuất cho SELECT, mặc dù nó không nhất thiết ảnh hưởng đến thứ tự của các hàng đó trong kết quả cuối cùng của UNION. Nếu ORDER BY xuất hiện mà không có LIMIT trong một LỰA CHỌN, nó sẽ được tối ưu hóa đi vì nó sẽ không có hiệu lực.

Câu cuối cùng của điều này là một chút sai lầm vì nó nên có một hiệu ứng. Việc tối ưu hóa này gây ra sự cố khi bạn ở trong tình huống cần đặt hàng trong truy vấn con.

Để buộc MySQL không thực hiện tối ưu hóa này, bạn có thể thêm mệnh đề LIMIT như sau:

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

Giá trị cao LIMITcó nghĩa là bạn có thể thêm một OFFSETtruy vấn tổng thể nếu bạn muốn thực hiện điều gì đó chẳng hạn như phân trang.

Điều này cũng mang lại cho bạn lợi ích bổ sung là có thể có ORDER BYcác cột khác nhau cho mỗi liên hợp.


0

Thử:

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

Trong đó [QUERY 1] và [QUERY 2] là hai truy vấn của bạn mà bạn muốn hợp nhất.


0

Điều này là do Bạn đang sắp xếp toàn bộ tập kết quả, Bạn nên sắp xếp, từng phần của liên hợp riêng biệt hoặc Bạn có thể sử dụng mệnh đề ORDER BY (Cái gì đó tức là khoảng cách truy vấn con) THEN (cái gì đó tức là id hàng)


0

Tôi đã thử thêm thứ tự theo từng truy vấn trước khi hợp nhất như

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

nhưng nó dường như không hoạt động. Nó không thực sự thực hiện thứ tự trong các hàng từ mỗi lựa chọn.

Tôi nghĩ rằng bạn sẽ cần phải giữ trật tự bên ngoài và thêm các cột trong mệnh đề where vào thứ tự theo, một cái gì đó như

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

Điều này có thể hơi phức tạp, vì bạn muốn nhóm theo phạm vi, nhưng tôi nghĩ điều đó có thể làm được.


user151841 union_sort ý tưởng dưới đây sẽ là một cách tốt đẹp để xử lý các nhóm
Mike C
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.