DISTINCT ON ของ PostgreSQL
เลือกหนึ่งแถวต่อกลุ่ม
DISTINCT ON ของ PostgreSQL เป็นบทเรียน SQL Academy ฟรีบน CoddyKit นี่คือบทเรียนที่ 3 จากทั้งหมด 4 บทเรียน คุณสามารถอ่านบทเรียนทั้งหมดด้านล่างฟรี — จากนั้นลองปฏิบัติด้วยตัวคุณเองในเบราว์เซอร์พร้อมตัวแก้ไขโค้ดในตัวและติวเตอร์ AI ตลอด 24/7 บทเรียนนี้เป็นส่วนหนึ่งของเส้นทางการเรียน SQL Academy และความก้าวหน้าของคุณจะซิงค์ข้ามเว็บและแอป CoddyKit คอร์ส SQL Academy มีบทเรียนทั้งหมด 4 บทเรียน
DISTINCT ON คืออะไร
PostgreSQL มีส่วนขยายที่ทรงพลังสำหรับคีย์เวิร์ดมาตรฐาน DISTINCT ซึ่งเรียกว่า DISTINCT ON ขณะที่ DISTINCT ปกติจะลบแถวที่ซ้ำกันทุกประการออก DISTINCT ON ช่วยให้คุณเลือกหนึ่งแถวต่อกลุ่มได้อย่างเจาะจง โดยอ้างอิงจากคอลัมน์หนึ่งคอลัมน์หรือมากกว่าที่คุณเลือก
ลองนึกภาพว่าเป็นคำสั่งว่า: 'สำหรับค่าแต่ละค่าที่ไม่ซ้ำกันในคอลัมน์นี้ ขอหนึ่งแถว' วิธีนี้มีประโยชน์อย่างมากเมื่อต้องการคำสั่งซื้อล่าสุดต่อลูกค้า คะแนนสูงสุดต่อนักเรียน หรือเหตุการณ์แรกต่อหมวดหมู่
ไวยากรณ์พื้นฐานของ DISTINCT ON
ไวยากรณ์จะวาง DISTINCT ON (column) ไว้ถัดจาก SELECT ทันที คอลัมน์ภายในวงเล็บจะกำหนดการจัดกลุ่ม — PostgreSQL จะส่งคืนหนึ่งแถวสำหรับค่าแต่ละค่าที่ไม่ซ้ำกันของคอลัมน์นั้น
ตัวอย่างด้านล่างส่งคืนหนึ่งแถวต่อ customer_id จากตารางคำสั่งซื้อ PostgreSQL จะเลือกแถวที่จะส่งคืนโดยอ้างอิงจากส่วนคำสั่ง ORDER BY ที่ตามมา
SELECT DISTINCT ON (customer_id)
customer_id,
order_id,
order_date,
total_amount
FROM orders
ORDER BY customer_id, order_date DESC;การเตรียมตารางตัวอย่าง
เรามาสร้างตาราง orders อย่างง่ายและเพิ่มแถวตัวอย่างเพื่อทดลองใช้ DISTINCT ON กัน เรามีลูกค้าสามราย โดยแต่ละรายมีคำสั่งซื้อหลายรายการในวันที่แตกต่างกัน
CREATE TABLE orders (
order_id SERIAL PRIMARY KEY,
customer_id INT,
order_date DATE,
total_amount NUMERIC(10, 2)
);
INSERT INTO orders (customer_id, order_date, total_amount) VALUES
(1, '2024-01-05', 120.00),
(1, '2024-03-12', 85.50),
(1, '2024-06-20', 200.00),
(2, '2024-02-14', 45.00),
(2, '2024-05-30', 310.00),
(3, '2024-04-01', 75.00);คำสั่งซื้อล่าสุดต่อลูกค้า
กรณีใช้งานที่พบบ่อยมากคือการค้นหาคำสั่งซื้อล่าสุดของลูกค้าแต่ละราย เมื่อเรียงลำดับ order_date DESC ภายในแต่ละกลุ่ม customer_id แล้ว DISTINCT ON จะเลือกแถวที่มีวันที่ล่าสุด
โปรดสังเกตว่าส่วนคำสั่ง ORDER BY ต้องเริ่มต้นด้วยคอลัมน์เดียวกันกับที่ระบุไว้ใน DISTINCT ON นี่เป็นข้อกำหนดของ PostgreSQL
SELECT DISTINCT ON (customer_id)
customer_id,
order_id,
order_date,
total_amount
FROM orders
ORDER BY customer_id, order_date DESC;คำสั่งซื้อแรกสุดต่อลูกค้า
หากต้องการคำสั่งซื้อรายการแรก (เก่าที่สุด)ต่อลูกค้าแต่ละราย ให้เปลี่ยนทิศทางการเรียงลำดับเป็น ASC ก็เพียงพอ ความแตกต่างมีเพียงลำดับของแถวภายในแต่ละกลุ่ม — DISTINCT ON จะเลือกแถวแรกหลังจากเรียงลำดับเสมอ
SELECT DISTINCT ON (customer_id)
customer_id,
order_id,
order_date,
total_amount
FROM orders
ORDER BY customer_id, order_date ASC;กฎของ ORDER BY
กฎสำคัญ: เมื่อใช้ DISTINCT ON (col) ส่วนคำสั่ง ORDER BY ต้องเริ่มต้นด้วยคอลัมน์เดียวกันกับที่ระบุไว้ภายใน DISTINCT ON หากไม่เป็นเช่นนั้น PostgreSQL จะแจ้งข้อผิดพลาด
หลังจากคอลัมน์ที่ใช้จัดกลุ่มแล้ว คุณสามารถเพิ่มเกณฑ์การเรียงลำดับใด ๆ เพื่อควบคุมว่าจะเลือกแถวใดภายในแต่ละกลุ่ม
-- Correct: ORDER BY starts with the DISTINCT ON column
SELECT DISTINCT ON (customer_id)
customer_id, order_date, total_amount
FROM orders
ORDER BY customer_id, total_amount DESC;
-- This would cause an error:
-- ORDER BY order_date DESC (missing customer_id at the start)คะแนนสูงสุดต่อนักเรียน
ต่อไปเป็นอีกตัวอย่างที่ใช้ตาราง test_scores เราต้องการคะแนนสูงสุดที่นักเรียนแต่ละคนเคยทำได้ เมื่อเรียงลำดับ score DESC ภายในกลุ่มของนักเรียนแต่ละคน DISTINCT ON จะส่งคืนเฉพาะแถวที่มีคะแนนสูงสุดของนักเรียนแต่ละคน
CREATE TABLE test_scores (
id SERIAL PRIMARY KEY,
student_id INT,
subject VARCHAR(50),
score INT,
taken_on DATE
);
INSERT INTO test_scores (student_id, subject, score, taken_on) VALUES
(101, 'Math', 92, '2024-02-10'),
(101, 'Math', 78, '2024-04-15'),
(102, 'Math', 85, '2024-02-10'),
(102, 'Math', 91, '2024-04-15'),
(103, 'Math', 67, '2024-02-10');
SELECT DISTINCT ON (student_id)
student_id, subject, score, taken_on
FROM test_scores
ORDER BY student_id, score DESC;DISTINCT ON กับหลายคอลัมน์
คุณสามารถจัดกลุ่มตามคอลัมน์มากกว่าหนึ่งคอลัมน์ได้โดยระบุหลายคอลัมน์ไว้ภายใน DISTINCT ON วิธีนี้จะส่งคืนหนึ่งแถวสำหรับชุดค่าผสมที่ไม่ซ้ำกันของคอลัมน์เหล่านั้นแต่ละชุด
ตัวอย่างด้านล่างเลือกคะแนนสูงสุดต่อนักเรียนต่อวิชา โดยถือว่าคู่แต่ละคู่ (นักเรียน, วิชา) เป็นกลุ่มของตนเอง
INSERT INTO test_scores (student_id, subject, score, taken_on) VALUES
(101, 'Science', 88, '2024-03-01'),
(101, 'Science', 95, '2024-05-20'),
(102, 'Science', 72, '2024-03-01');
SELECT DISTINCT ON (student_id, subject)
student_id, subject, score, taken_on
FROM test_scores
ORDER BY student_id, subject, score DESC;การกรองด้วย WHERE
DISTINCT ON ทำงานร่วมกับส่วนคำสั่ง WHERE ได้อย่างเป็นธรรมชาติ ตัวกรองจะถูกนำไปใช้ก่อน จากนั้น DISTINCT ON จะเลือกหนึ่งแถวต่อกลุ่มจากผลลัพธ์ที่กรองแล้ว
ในที่นี้ เราค้นหาคำสั่งซื้อล่าสุดต่อลูกค้า แต่เฉพาะคำสั่งซื้อที่มียอดเกิน 100
SELECT DISTINCT ON (customer_id)
customer_id,
order_id,
order_date,
total_amount
FROM orders
WHERE total_amount > 100
ORDER BY customer_id, order_date DESC;DISTINCT ON เทียบกับ GROUP BY
ทั้ง DISTINCT ON และ GROUP BY สามารถสร้างหนึ่งแถวต่อกลุ่มได้ แต่มีจุดประสงค์แตกต่างกัน:
- GROUP BY รวมแถวเข้าด้วยกัน และต้องใช้ฟังก์ชันรวม เช่น SUM, MAX และอื่น ๆ สำหรับคอลัมน์ที่ไม่ได้จัดกลุ่ม
- DISTINCT ON จะคงแถวที่มีอยู่จริงไว้ — คุณจึงเข้าถึงคอลัมน์ทั้งหมดได้โดยไม่ต้องใช้การรวมค่า
ใช้ GROUP BY เมื่อต้องการค่าที่ผ่านการรวม ใช้ DISTINCT ON เมื่อต้องการข้อมูลทั้งหมดจากแถวที่เจาะจงภายในแต่ละกลุ่ม
-- GROUP BY: only aggregated columns allowed
SELECT customer_id, MAX(order_date) AS latest_date
FROM orders
GROUP BY customer_id;
-- DISTINCT ON: returns the whole row for that latest date
SELECT DISTINCT ON (customer_id)
customer_id, order_id, order_date, total_amount
FROM orders
ORDER BY customer_id, order_date DESC;การใช้ DISTINCT ON ในคิวรีย่อย
บางครั้งคุณอาจต้องกรองหรือเรียงลำดับเพิ่มเติมจากผลลัพธ์ของ DISTINCT ON เนื่องจาก ORDER BY ด้านนอกผูกอยู่กับคอลัมน์ที่ใช้จัดกลุ่ม คุณจึงสามารถครอบคิวรีไว้ในคิวรีย่อย (หรือ CTE) เพื่อใช้การเรียงลำดับแบบอื่นกับผลลัพธ์สุดท้าย
ตัวอย่างนี้เลือกคำสั่งซื้อล่าสุดต่อลูกค้าก่อน แล้วจึงเรียงลำดับผลลัพธ์สุดท้ายตาม total_amount จากมากไปน้อย
SELECT *
FROM (
SELECT DISTINCT ON (customer_id)
customer_id,
order_id,
order_date,
total_amount
FROM orders
ORDER BY customer_id, order_date DESC
) AS latest_orders
ORDER BY total_amount DESC;ตรวจสอบความเข้าใจ
มาทดสอบความเข้าใจของคุณเกี่ยวกับ DISTINCT ON กัน โปรดอ่านคิวรีด้านล่างอย่างละเอียด แล้วเลือกคำตอบที่อธิบายสิ่งที่คิวรีส่งคืนได้ดีที่สุด
SELECT DISTINCT ON (department_id) department_id, employee_name, salary FROM employees ORDER BY department_id, salary DESC;
สรุปบทเรียน
ทำได้ยอดเยี่ยมมาก! ต่อไปนี้คือสรุปสิ่งที่คุณได้เรียนรู้เกี่ยวกับ PostgreSQL DISTINCT ON:
DISTINCT ON (col)ส่งคืนหนึ่งแถวพอดีต่อค่าแต่ละค่าที่ไม่ซ้ำกันของคอลัมน์ที่ระบุ- ส่วนคำสั่ง
ORDER BYต้องเริ่มต้นด้วยคอลัมน์เดียวกันกับที่ระบุไว้ในDISTINCT ON— ส่วนนี้ควบคุมว่าจะเลือกแถวใดจากแต่ละกลุ่ม - คุณสามารถใช้หลายคอลัมน์ได้:
DISTINCT ON (col1, col2)จะจัดกลุ่มตามชุดค่าผสมของทั้งสองคอลัมน์ - ต่างจาก
GROUP BYตรงที่DISTINCT ONส่งคืนแถวจริงพร้อมคอลัมน์เดิมทั้งหมด — ไม่จำเป็นต้องรวมค่า - ครอบคิวรีไว้ในคิวรีย่อยเมื่อต้องการเรียงลำดับผลลัพธ์สุดท้ายตามคอลัมน์อื่น
DISTINCT ON เป็นคุณลักษณะเฉพาะของ PostgreSQL และเป็นหนึ่งในวิธีที่สง่างามที่สุดสำหรับแก้ปัญหา 'เลือกหนึ่งแถวต่อกลุ่ม'
คำถามที่พบบ่อย
บทเรียน “DISTINCT ON ของ PostgreSQL” ฟรีหรือไม่
ใช่ — ข้อความเต็มของ “DISTINCT ON ของ PostgreSQL” ฟรีให้อ่านที่นี่บนเว็บ เพื่อปฏิบัติแบบโต้ตอบ (ตัวแก้ไขโค้ดในตัวและติวเตอร์ AI ตลอด 24/7) และปลดล็อคส่วนที่เหลือของคอร์ส SQL Academy ให้อัปเกรดเป็น CoddyKit PRO คอร์ส SQL Academy มีบทเรียนทั้งหมด 4 บทเรียน
คุณจะเรียนรู้อะไรในบทเรียน “DISTINCT ON ของ PostgreSQL”
เลือกหนึ่งแถวต่อกลุ่ม คุณปฏิบัติ SQL Academy ด้วยโค้ดที่ใช้งานได้จริงที่คุณเรียกใช้โดยตรงในเบราว์เซอร์ และติวเตอร์ AI ตลอด 24/7 ตอบคำถามของคุณขณะที่คุณไปผ่านบทเรียน
คุณต้องมีประสบการณ์ก่อนที่จะเริ่มเรียน SQL Academy หรือไม่
ไม่จำเป็นต้องมีประสบการณ์มาก่อน SQL Academy บน CoddyKit ออกแบบมาสำหรับผู้เริ่มต้นไปจนถึงผู้เรียนขั้นสูง คุณสามารถเริ่มต้นที่นี่หรือเริ่มจากตัวแรกและเรียนด้วยความเร็วของคุณเอง นี่คือบทเรียนที่ 3 จากทั้งหมด 4 บทเรียน
บทเรียน “DISTINCT ON ของ PostgreSQL” ใช้เวลานานแค่ไหน
บทเรียน CoddyKit ส่วนใหญ่ใช้เวลาประมาณ 5–10 นาที แต่ละบทเรียนจึงสั้นและเป็นแบบโต้ตอบ คุณสามารถก้าวหน้าอย่างต่อเนื่องและกลับมาเรียนต่อจากตรงที่เพิ่งหยุดบนเว็บและแอปได้เลย
ฉันเขียนและรันโค้ดในบทเรียน SQL Academy นี้ได้ไหม
ได้ บทเรียน SQL Academy ทุกบทมีตัวแก้ไขโค้ดในตัว คุณจึงเขียนและรันโค้ดจริงได้เลยในเบราว์เซอร์ และได้รับข้อเสนอแนะจาก AI ในทันที — ไม่ต้องติดตั้งในเครื่องของคุณ
บทเรียนทั้งหมดในหลักสูตรนี้
- พื้นฐาน SELECT DISTINCT
- DISTINCT ในหลายคอลัมน์
- DISTINCT ON ของ PostgreSQL
- การนับค่าที่ไม่ซ้ำกัน