sql ORDER BY หลายค่าตามลำดับที่ระบุ?


99

โอเคฉันมีตารางที่มีคีย์ที่จัดทำดัชนีและไม่มีฟิลด์ที่จัดทำดัชนี ฉันต้องการค้นหาระเบียนทั้งหมดที่มีค่าหนึ่งและส่งคืนแถว ฉันต้องการทราบว่าฉันสามารถสั่งซื้อหลายค่าได้หรือไม่

ตัวอย่าง:

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

pseudo: ต้องการให้ผลลัพธ์เป็นแบบนี้ 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'

ดังนั้นผลลัพธ์จะเป็น:

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

ไวยากรณ์ถูกต้อง แต่เมื่อฉันดำเนินการสืบค้นจะไม่ส่งคืนผลลัพธ์ใด ๆ แม้ว่าฉันจะ จำกัด ไว้ที่ 1 ระเบียนก็ตาม มีวิธีอื่นที่จะไปเกี่ยวกับเรื่องนี้หรือไม่?

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

สิ่งที่ฉันทำไม่ได้:

  • GROUP BY เนื่องจากฉันต้องการส่งคืนค่าระเบียนเฉพาะ
  • WHERE x_field IN ('f', 'p', 'i', 'a') ฉันต้องการค่าทั้งหมดเนื่องจากฉันพยายามใช้แบบสอบถามเดียวสำหรับการทดสอบการตรวจสอบความถูกต้องหลายรายการ และค่า x_field ไม่ได้อยู่ในลำดับ DESC / ASC

หลังจากเขียนคำถามนี้ฉันเริ่มคิดว่าฉันต้องคิดใหม่ฮ่า ๆ !


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

คำตอบ:


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

29

คุณสามารถใช้ LEFT JOIN กับ "VALUES ('f', 1), ('p', 2), ('a', 3), ('i', 4)" และใช้คอลัมน์ที่สองในลำดับของคุณ - โดยการแสดงออก Postgres จะใช้การเข้าร่วมแฮชซึ่งจะเร็วกว่ากรณีใหญ่มากหากคุณมีค่ามาก และง่ายกว่าในการสร้างอัตโนมัติ

หากข้อมูลการสั่งซื้อนี้ได้รับการแก้ไขแล้วควรมีตารางของตัวเอง


6
นี่เป็นทางออกที่ดีที่สุด!
jnns

28

ลอง:

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

คุณมาถูกทางแล้ว แต่ด้วยการใส่ x_field เฉพาะในค่า F อีก 3 ตัวจะถือว่าเป็นค่าคงที่และไม่ได้เปรียบเทียบกับสิ่งใด ๆ ในชุดข้อมูล


Postgres สนับสนุนบูลีนโดยนัยหรือไม่ ถ้าเป็นเช่นนั้นบูลีนเรียงลำดับอย่างไร
gbn

ฉันชอบวิธีแก้ปัญหานี้ แต่มันไม่ได้กลับมาอีกเลย
Phill Pafford

@gbn ใช่และเท็จ <จริง. ฉันคาดหวังว่าสิ่งนี้จะได้ผล
Andrew Lazarus

7
ใช่มันใช้งานได้ใน Postgres หมายเหตุสำหรับโซลูชันนี้คือคุณได้รับผลลัพธ์ที่เรียงลำดับย้อนกลับ ดังนั้นคุณต้องใส่ฟิลด์ในลำดับย้อนกลับ: ORDER BY x_field = 'A', x_field = 'I', x_field = 'P', x_field = 'F',
igo

16

ใช้caseสวิตช์เพื่อแปลรหัสเป็นตัวเลขที่สามารถจัดเรียงได้:

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

11

ฉันพบวิธีแก้ปัญหาที่สะอาดกว่ามากสำหรับสิ่งนี้:

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

หมายเหตุ: array_position ต้องการ Postgres v9.5 หรือสูงกว่า


1
สิ่งสำคัญที่ควรทราบว่า array_position () มีเฉพาะใน Postgres v9.5 เป็นต้นไป afaik
bigsee

ขอบคุณมากชอบวิธีนี้มากสำหรับวิธีการของ CASE ทำงานร่วมกับจำนวนเต็มด้วย array_position(ARRAY[1, 0]::integer[], x_field)
Paul Watson

7

CASEและORDER BYข้อเสนอแนะควรทำงานทั้งหมด แต่ผมจะขอแนะนำให้ม้ามีสีที่แตกต่างกัน สมมติว่ามีค่าเพียงจำนวนที่เหมาะสมx_fieldและคุณรู้แล้วว่าคืออะไรสร้างประเภทที่แจกแจงโดยมี F, P, A และ I เป็นค่า (บวกค่าอื่น ๆ ที่เป็นไปได้) Enums จะเรียงตามลำดับโดยนัยโดยCREATEคำสั่งของพวกเขา นอกจากนี้คุณยังสามารถใช้ชื่อที่มีค่าที่มีความหมายได้ซึ่งแอปพลิเคชันจริงของคุณอาจทำได้และคุณได้ปิดบังไว้เพื่อเป็นความลับโดยไม่ต้องเสียพื้นที่เพราะจะจัดเก็บเฉพาะตำแหน่งลำดับเท่านั้น


1

คุณสามารถเรียงลำดับตามคอลัมน์ที่เลือกหรือนิพจน์อื่น ๆ

นี่คือตัวอย่างวิธีการเรียงลำดับตามผลลัพธ์ของ case-statement:

  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

ผลลัพธ์จะเป็นรายการที่เริ่มต้นด้วยแถว "IsGen = 0" ตามด้วยแถว "IsGen = 1" และแถวอื่น ๆ ทั้งหมดต่อท้าย

คุณสามารถเพิ่มพารามิเตอร์คำสั่งซื้อเพิ่มเติมได้ในตอนท้าย:

  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

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

0

สำหรับคนที่เพิ่งเริ่มORDER BYกับCASEสิ่งนี้อาจเป็นประโยชน์

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

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