การใช้ยูเนี่ยนและลำดับตามข้อใน mysql


123

ฉันต้องการใช้ order by กับ union ในแบบสอบถาม mysql ฉันกำลังดึงข้อมูลประเภทต่างๆตามเกณฑ์ที่แตกต่างกันจากตารางตามระยะทางสำหรับการค้นหาบนไซต์ของฉัน คำค้นหาแรกที่เลือกจะแสดงผลข้อมูลที่เกี่ยวข้องกับการค้นหาสถานที่ที่แน่นอน คำค้นหาที่เลือกครั้งที่ 2 จะส่งคืนข้อมูลที่เกี่ยวข้องกับระยะทางภายใน 5 กม. จากสถานที่ที่ค้นหา แบบสอบถามแบบเลือกที่ 3 จะส่งคืนข้อมูลที่เกี่ยวข้องกับระยะทางภายใน 5-15 กม. จากสถานที่ที่ค้นหา

จากนั้นฉันใช้ยูเนี่ยนเพื่อรวมผลลัพธ์ทั้งหมดและแสดงบนเพจที่มีเพจจิ้ง ภายใต้หัวข้อที่เหมาะสมเป็น'ผลการค้นหาที่แน่นอน' , 'ผลลัพธ์ภายใน 5 กม.'เป็นต้น

ตอนนี้ฉันต้องการจัดเรียงผลลัพธ์ตาม id หรือ add_date แต่เมื่อฉันเพิ่มลำดับตามส่วนคำสั่งที่ส่วนท้ายของแบบสอบถามของฉัน (query1 union query 2 union query 3 order by add_date) มันเรียงลำดับผลลัพธ์ทั้งหมด แต่สิ่งที่ฉันต้องการคือควรเรียงลำดับภายใต้แต่ละหัวข้อ


ประเภทใดคือ / เป็นเขตข้อมูลที่คุณต้องการจัดเรียงในแต่ละตาราง
user151841

คำตอบ:


221

คุณสามารถทำได้โดยเพิ่มคอลัมน์หลอกที่มีชื่ออันดับให้กับการเลือกแต่ละครั้งซึ่งคุณสามารถจัดเรียงตามลำดับแรกก่อนที่จะจัดเรียงตามเกณฑ์อื่น ๆ ของคุณเช่น:

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
ทำไมมีaและจุดจบ?
Uday Hiwarale

25
MySQL ต้องการให้ตารางที่สืบทอดมามีนามแฝง
RedFilter

4
@RedFilter ฉันไม่ค่อยเข้าใจ อะไรคือจุดรวมของ "เลือกทั้งหมดเป็นตารางที่ได้มา" เมื่อเราสามารถเลือกทั้ง 3 ตารางแล้วทำorder by? ( "ในการจัดเรียงหรือ จำกัดUNIONผลลัพธ์ทั้งหมดให้ใส่วงเล็บของแต่ละSELECTข้อความและวางORDER BYหรืออยู่LIMITหลังสุดท้าย" ) เปรียบเทียบรหัสของคุณกับi.stack.imgur.com/LpTMU.png
Pacerier

1
@Pacerier ถ้าไวยากรณ์นั้นใช้ได้กับ MySQL ไปเลย! ไวยากรณ์ของฉันเป็นข้ามแพลตฟอร์มเล็กน้อยโดยทั่วไปฉันไม่ได้ทำงานกับ MySQL จริงๆแล้วฉันชอบมันมากกว่าเพราะมันใช้งานได้ในกรณีทั่วไปมากกว่าเช่นพิจารณาว่าเมื่อใดที่คุณต้องการเพียงสิบรายการแรกจากแบบสอบถาม UNION สุดท้าย - ฉันคิดว่าคุณจะต้องถอยกลับไปที่ไวยากรณ์ของฉันอยู่ดี
RedFilter

1
@Pacerier ให้พิจารณาด้วยว่าค่าด้วยวิธีนี้ช่วยให้ "select *" ด้านบนเป็น "select id, add_date" และดึง "rank" ออกจากผลลัพธ์ได้หากคุณไม่ต้องการเห็น
Dev Null

45

คุณสามารถใช้แบบสอบถามย่อยเพื่อทำสิ่งนี้:

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 ดีในการแยกคำสั่งซื้อ นอกจากนี้เรายังสามารถจัดเรียงที่แตกต่างกันได้หากประโยคคำสั่งเป็นเรื่องธรรมดา แต่เราต้องการให้ผลลัพธ์แยกออกจากกัน (แทนที่จะแยกคำสั่ง): 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
สิ่งนี้ไม่ถูกต้อง : การใช้ORDER BYสำหรับแต่ละSELECTคำสั่งไม่มีนัยอะไรเกี่ยวกับลำดับที่แถวปรากฏในผลลัพธ์สุดท้าย
shmosel

คุณพูดถูกคำตอบที่ยอมรับก็เป็นคำตอบที่ถูกต้องเช่นกัน สิ่งนี้เพิ่งเกิดขึ้นได้ดีเมื่อฉันทดสอบ
rickythefox

shmosel (และ rickythefox) - ยูเนี่ยนทั้งหมดไม่ได้ลบรายการที่ซ้ำกันดังนั้นจึงไม่มีเหตุผลที่จะเปลี่ยนประเภทของการจัดเรียงที่คุณเลือก นี่คือเหตุผลว่าทำไมมันถึงได้ผลสำหรับคุณในอดีตและทำไมมันถึงเหมาะกับคุณในอนาคต ลำดับที่สับสนในผลลัพธ์สุดท้ายเกิดจาก UNION (DISTINCT) ต้องการการจัดเรียงบางประเภทเพื่อรวมแถวอย่างมีประสิทธิภาพ หรือโดยเฉพาะอย่างยิ่งเรียงลำดับเนื่องจากรวมแถวได้อย่างมีประสิทธิภาพ ดังนั้นคุณสามารถพึ่งพาสหภาพทั้งหมดเพื่อรักษาแบบสอบถามย่อยของคุณ
Gerard ONeill

2
วิธีนี้ใช้งานได้ดีสำหรับ MySQL เวอร์ชันเก่าตอนนี้วิธีนี้จะใช้ไม่ได้ เนื่องจากมาตรฐาน SQL ไม่รับประกันว่าจะรักษาลำดับของแบบสอบถามย่อย
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

สิ่งนี้ได้ผล แต่ฉันต้องเปลี่ยนสิ่งหนึ่งที่ผิดปกติ: ฉันต้องให้นามแฝงที่ใช้ร่วมกันกับฟิลด์ที่สั่งซื้อโดย ทำงานนอกเหนือจากนั้นขอบคุณ!
HoldOffHunger

9

แบบสอบถามแบบร่วมสามารถมีได้เพียงหนึ่งORDER BYประโยคหลักIIRC จะได้รับนี้ในแบบสอบถามแต่ละทำขึ้นมากขึ้นUNIONสอบถามข้อมูลเพิ่มที่จะเป็นหนึ่งในเขตข้อมูลที่คุณจัดเรียงสินค้าสำหรับ'sUNIONORDER BY

ตัวอย่างเช่นคุณอาจมีบางอย่างเช่น

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

ที่union_sortสนามสามารถเป็นอะไรก็ได้ที่คุณอาจต้องการที่จะเรียงลำดับตาม ในตัวอย่างนี้เพียงแค่ใส่ผลลัพธ์จากตารางแรกก่อนตารางที่สองที่สองเป็นต้น


9

อย่าลืมว่าการรวมกันทั้งหมดเป็นวิธีการเพิ่มระเบียนลงในชุดระเบียนโดยไม่ต้องเรียงลำดับหรือรวมกัน (ตรงข้ามกับการรวมกัน)

ตัวอย่างเช่น:

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

ช่วยให้แต่ละแบบสอบถามชัดเจนขึ้นและช่วยให้คุณสามารถจัดเรียงตามพารามิเตอร์ที่แตกต่างกันในแต่ละแบบสอบถาม อย่างไรก็ตามการใช้คำตอบที่เลือกไว้มันอาจจะชัดเจนขึ้นขึ้นอยู่กับความซับซ้อนและความเกี่ยวข้องของข้อมูลนั้นเป็นเพราะคุณกำลังกำหนดแนวคิดในการจัดเรียง นอกจากนี้ยังช่วยให้คุณสามารถส่งคืนคอลัมน์เทียมไปยังโปรแกรมสืบค้นข้อมูลเพื่อให้มีบริบทที่สามารถจัดเรียงหรือจัดระเบียบได้

แต่วิธีนี้มีข้อดีคือรวดเร็วไม่แนะนำตัวแปรพิเศษและทำให้ง่ายต่อการแยกแบบสอบถามแต่ละรายการรวมถึงการจัดเรียง ความสามารถในการเพิ่มขีด จำกัด เป็นเพียงโบนัสพิเศษ

และแน่นอนว่าอย่าลังเลที่จะเปลี่ยนสหภาพทั้งหมดให้เป็นสหภาพและเพิ่มการเรียงลำดับสำหรับข้อความค้นหาทั้งหมด หรือเพิ่มรหัสเทียมซึ่งในกรณีนี้วิธีนี้จะทำให้ง่ายต่อการจัดเรียงตามพารามิเตอร์ที่แตกต่างกันในแต่ละแบบสอบถาม แต่จะเหมือนกับคำตอบที่ยอมรับ


4

ฉันได้รับสิ่งนี้ในการรวมบวกสหภาพ

(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

เมื่อคุณใช้ORDER BYอนุประโยคภายในแบบสอบถามย่อยที่ใช้ร่วมกับUNIONmysql จะทำให้ORDER BYอนุประโยคนั้นเหมาะสมที่สุด

เนื่องจากโดยค่าเริ่มต้นUNIONจะส่งคืนรายการที่ไม่เรียงลำดับดังนั้นจึงORDER BYไม่ต้องทำอะไรเลย

การเพิ่มประสิทธิภาพถูกกล่าวถึงในเอกสารและกล่าวว่า:

ในการนำ ORDER BY หรือ LIMIT ไปใช้กับแต่ละ SELECT ให้วางส่วนคำสั่งไว้ในวงเล็บที่ล้อมรอบ 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);

อย่างไรก็ตามการใช้ ORDER BY สำหรับคำสั่ง SELECT แต่ละคำไม่ได้หมายความว่าไม่มีอะไรเกี่ยวกับลำดับที่แถวปรากฏในผลลัพธ์สุดท้ายเนื่องจาก UNION โดยค่าเริ่มต้นจะสร้างชุดแถวที่ไม่เรียงลำดับ ดังนั้นโดยทั่วไปการใช้ ORDER BY ในบริบทนี้จะใช้ร่วมกับ LIMIT เพื่อที่จะใช้เพื่อกำหนดส่วนย่อยของแถวที่เลือกเพื่อดึงข้อมูลสำหรับ SELECT แม้ว่าจะไม่จำเป็นต้องมีผลต่อลำดับของแถวเหล่านั้นใน ผลลัพธ์สุดท้ายของ UNION หาก ORDER BY ปรากฏโดยไม่มี LIMIT ใน SELECT ระบบจะปรับให้เหมาะสมที่สุดเพราะจะไม่มีผลใด ๆ

ประโยคสุดท้ายนี้ทำให้เข้าใจผิดเล็กน้อยเพราะมันน่าจะมีผล การเพิ่มประสิทธิภาพนี้ทำให้เกิดปัญหาเมื่อคุณอยู่ในสถานการณ์ที่คุณต้องสั่งซื้อภายในแบบสอบถามย่อย

ในการบังคับให้ MySQL ไม่ทำการเพิ่มประสิทธิภาพนี้คุณสามารถเพิ่ม LIMIT clause ดังนี้:

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

ค่าสูงLIMITหมายความว่าคุณสามารถเพิ่มOFFSETข้อความค้นหาโดยรวมได้หากคุณต้องการทำบางอย่างเช่นการแบ่งหน้า

นอกจากนี้ยังช่วยให้คุณได้รับประโยชน์เพิ่มเติมจากความสามารถในORDER BYคอลัมน์ต่างๆสำหรับแต่ละสหภาพ


0

ลอง:

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

โดยที่ [QUERY 1] และ [QUERY 2] คือคำค้นหาสองรายการของคุณที่คุณต้องการรวมเข้าด้วยกัน


0

เนื่องจากคุณกำลังจัดเรียงชุดผลลัพธ์ทั้งหมดคุณควรเรียงลำดับทุกส่วนของการรวมกันแยกจากกันหรือคุณสามารถใช้ ORDER BY (บางอย่างเช่นระยะการสืบค้นย่อย) แล้ว (บางอย่างเช่นรหัสแถว)


0

ฉันพยายามเพิ่มลำดับโดยในแต่ละแบบสอบถามก่อนที่จะรวมกันเช่น

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

แต่ดูเหมือนจะไม่ได้ผล มันไม่ได้ทำการเรียงลำดับภายในแถวจากการเลือกแต่ละครั้ง

ฉันคิดว่าคุณจะต้องรักษาลำดับโดยอยู่ด้านนอกและเพิ่มคอลัมน์ในที่ซึ่งส่วนคำสั่งในลำดับโดยบางอย่างเช่น

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

นี่อาจจะยุ่งยากเล็กน้อยเนื่องจากคุณต้องการจัดกลุ่มตามช่วง แต่ฉันคิดว่ามันน่าจะทำได้


แนวคิดของผู้ใช้ 151841 union_sort ด้านล่างนี้เป็นวิธีที่ดีในการจัดการการจัดกลุ่ม
Mike C
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.