วิธีการเลือกที่แตกต่างกันสำหรับหนึ่งคอลัมน์และในคอลัมน์อื่น?


29

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

key     value
===     =====
one     test
one     another
one     value
two     goes
two     here
two     also
three   example

ฉันต้องการกลับแถวตัวอย่างหนึ่งแถวเลือกโดยพลจากคีย์ที่แตกต่างกันแต่ละอันบางทีรับสามแถวเหล่านี้:

key     value
===     =====
one     test
two     goes
three   example

ฉันจะกำหนดแบบสอบถามดังกล่าวใน SQL ได้อย่างไร


2
DBMS ใด (Oracle, SQL-Server, DB2, MySQL, Postgres)
ypercubeᵀᴹ

1
มันเป็นระบบที่เป็นกรรมสิทธิ์
WilliamKF

คำตอบ:


33

แบบสอบถามที่ง่ายที่สุดในการเขียนสำหรับ MySQL (ที่มีการตั้งค่า ANSI ไม่เข้มงวด) ใช้การก่อสร้างที่ไม่ได้มาตรฐาน:

SELECT key, value
FROM tableX
GROUP BY key ;

ในเวอร์ชันล่าสุด (5.7 และ 8.0+) ซึ่งเป็นการตั้งค่าที่เข้มงวดและONLY_FULL_GROUP_BYเป็นค่าเริ่มต้นคุณสามารถใช้ANY_VALUE()ฟังก์ชันเพิ่มใน 5.7:

SELECT key, ANY_VALUE(value) AS value
FROM tableX
GROUP BY key ;

สำหรับ DBMS อื่น ๆ ที่มีฟังก์ชั่นหน้าต่าง (เช่น Postgres, SQL-Server, Oracle, DB2) คุณสามารถใช้สิ่งเหล่านี้ได้ ข้อดีคือคุณสามารถเลือกคอลัมน์อื่น ๆ ในผลลัพธ์ได้เช่นกัน (นอกเหนือจากkeyและvalue):

SELECT key, value
FROM tableX
    ( SELECT key, value,
             ROW_NUMBER() OVER (PARTITION BY key 
                                ORDER BY whatever)     --- ORDER BY NULL
               AS rn                                   --- for example
      FROM tableX
    ) tmp 
WHERE rn = 1 ;

สำหรับเวอร์ชันเก่าของข้างต้นและสำหรับ DBMS อื่น ๆ เป็นวิธีทั่วไปที่ทำงานได้เกือบทุกที่ ข้อเสียอย่างหนึ่งคือคุณไม่สามารถเลือกคอลัมน์อื่นด้วยวิธีนี้ อีกอย่างคือฟังก์ชั่นรวมที่ชอบMIN()และMAX()ไม่ทำงานกับบางประเภทข้อมูลในบาง DBMS (เช่นบิต, ข้อความ, blobs):

SELECT key, MIN(value) AS value
FROM tableX
GROUP BY key ;

PostgreSQL มีDISTINCT ONโอเปอเรเตอร์ที่ไม่ได้มาตรฐานซึ่งสามารถใช้ได้เช่นกัน ตัวเลือกORDER BYสำหรับการเลือกแถวจากทุกกลุ่มที่ควรเลือก:

SELECT DISTINCT ON (key) key, value
FROM tableX
-- ORDER BY key, <some_other_expressions> ;

2
@WilliamKF หาก "เลือกโดยพลการ" คุณหมายถึง "เลือกแบบสุ่ม" จากนั้นให้แทนที่ORDER BY whateverคำค้นหาใน ypercube ด้วยการเรียกใช้ฟังก์ชันเพื่อสุ่มผลลัพธ์
Leigh Riffel

1
@ LeighRiffel มันไม่จำเป็นต้องสุ่มเลือกใด ๆ ที่ง่ายเหมือนคนแรกที่พบว่าทำงานได้ดี
WilliamKF

3

สำหรับเซิร์ฟเวอร์ MS-SQl:

;with FinalDataset as
(
    select *,
        row_number() over(partition by key order by value) as rownum
    from YourOriginalTable
)
select
   key,
   value
from FinalDataset 
where rownum = 1

ในทำนองเดียวกันคุณอาจมี rownum = 2 สำหรับชุดผลลัพธ์ที่สองของคุณ


2

คล้ายกับคำตอบที่ยอมรับ แต่แทนที่จะเป็น min () หรือ max () คุณสามารถใช้ array_agg ()

SELECT key, (array_agg(value))[1] AS value
FROM tableX
GROUP BY key ;

คุณสามารถเลือกที่จะเรียงลำดับค่าภายในอาร์เรย์เพื่อเลือกค่าที่ใหญ่ที่สุด

SELECT key, (array_agg(value) ORDER BY value DESC)[1] AS value
FROM tableX
GROUP BY key ;

(ตรวจสอบบน PostgreSQL)

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