0Pricing
SQL Academy · บทเรียน

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 ในทันที — ไม่ต้องติดตั้งในเครื่องของคุณ

บทเรียนทั้งหมดในหลักสูตรนี้

  1. พื้นฐาน SELECT DISTINCT
  2. DISTINCT ในหลายคอลัมน์
  3. DISTINCT ON ของ PostgreSQL
  4. การนับค่าที่ไม่ซ้ำกัน
← กลับไปที่ SQL Academy