PlusMagi's Blog By Pitt Phunsanit Ai,Database การหาค่าก่อนหน้าและถัดไป: การใช้ LEAD() และ LAG() ในการเปรียบเทียบข้อมูลระหว่าง Row

การหาค่าก่อนหน้าและถัดไป: การใช้ LEAD() และ LAG() ในการเปรียบเทียบข้อมูลระหว่าง Row

ในโลกของการวิเคราะห์ข้อมูลเชิงลึก (Advanced Data Analytics) ข้อมูลส่วนใหญ่ไม่ได้ถูกพิจารณาแบบโดดเดี่ยว แต่เป็นชุดของเหตุการณ์ที่เกิดขึ้นตามลำดับเวลา (Time Series) หรือขั้นตอนการดำเนินงาน การทำความเข้าใจว่าค่า ณ จุดใดจุดหนึ่งมีความสัมพันธ์อย่างไรกับสิ่งที่เกิดขึ้นก่อนหน้า (Previous) และหลังจากนั้น (Next) จึงเป็นหัวใจสำคัญในการค้นพบรูปแบบ (Pattern) การระบุแนวโน้ม (Trend) หรือการตรวจจับความผิดปกติ (Anomaly Detection) หากเราต้องการเปรียบเทียบยอดขายวันนี้กับเมื่อวาน หรือดูว่าสถานะของผู้ใช้มีการเปลี่ยนแปลงอย่างไรจากรอบล่าสุด การใช้ฟังก์ชัน SQL พื้นฐานอาจไม่เพียงพอ

ทำความรู้จักกับ Window Functions: LEAD() และ LAG()

ฟังก์ชัน Window Function เช่น LEAD() และ LAG() คือเครื่องมือทรงพลังระดับ Senior Architect ใน PostgreSQL ที่ช่วยให้เราสามารถ “มองข้าม” ข้อมูลไปที่แถวก่อนหน้า (Lag) หรือแถวถัดไป (Lead) ได้อย่างมีประสิทธิภาพ โดยไม่ต้องใช้ Self-Join ที่ซับซ้อนและกินทรัพยากรมากนัก

แนวคิดหลักคือการกำหนด ‘หน้าต่าง’ ของข้อมูล (Window Partition) ซึ่งเป็นการแบ่งชุดข้อมูลออกเป็นกลุ่มย่อย ๆ ตามเงื่อนไขที่กำหนด (เช่น แบ่งตาม Product ID) และจากนั้นจึงระบุว่าเราต้องการค่าที่ห่างออกไปกี่แถว (Offset) จากแถวปัจจุบัน

หลักการทำงานของ LEAD() และ LAG()

  • LAG(column, offset, default_value): จะดึงค่าจากคอลัมน์ที่กำหนดในแถวก่อนหน้าตามจำนวน offset ที่ระบุ หากไม่มีค่าในแถวก่อนหน้า จะใช้ค่า default_value แทน
  • LEAD(column, offset, default_value): จะทำหน้าที่ตรงกันข้าม คือการดึงค่าจากแถวถัดไปตามจำนวน offset ที่กำหนด

การใช้งานที่สมบูรณ์จะต้องระบุ OVER (PARTITION BY ... ORDER BY ...) เสมอ เพื่อกำหนดขอบเขตและลำดับของการเปรียบเทียบ

ตัวอย่างการใช้งานจริงใน PostgreSQL

สมมติว่าเรามีตารางข้อมูลยอดขายรายวัน (sales_data) และต้องการเปรียบเทียบยอดขายของวันนี้กับยอดขายของเมื่อวานและวันพรุ่งนี้

SQL

-- 1. สร้างตารางจำลอง (Setup) และใส่ข้อมูลตัวอย่าง
CREATE TABLE sales_data (
    sale_date DATE,
    product VARCHAR(50),
    sale_amount NUMERIC
);

INSERT INTO sales_data (sale_date, product, sale_amount) VALUES
('2023-10-01', 'A', 100.00),
('2023-10-02', 'A', 150.00),
('2023-10-03', 'A', 120.00),
('2023-10-01', 'B', 50.00),
('2023-10-02', 'B', 70.00);

-- 2. ใช้ LAG() และ LEAD() เพื่อเปรียบเทียบ
SELECT
    sale_date,
    product,
    sale_amount,
    -- ดึงค่าก่อนหน้า (LAG): ยอดขายของเมื่อวาน
    LAG(sale_amount, 1) OVER (PARTITION BY product ORDER BY sale_date) AS previous_day_sale,
    -- ดึงค่าถัดไป (LEAD): ยอดขายของวันพรุ่งนี้
    LEAD(sale_amount, 1) OVER (PARTITION BY product ORDER BY sale_date) AS next_day_sale
FROM
    sales_data
ORDER BY
    product, sale_date;

คำอธิบายโค้ด:

  • PARTITION BY product: กำหนดให้การคำนวณเกิดขึ้นแยกกันตามสินค้าแต่ละชนิด (A และ B)
  • ORDER BY sale_date: กำหนดลำดับการเปรียบเทียบตามวันที่
  • LAG(sale_amount, 1): ดึงค่า sale_amount จากแถวก่อนหน้า 1 แถว
  • LEAD(sale_amount, 1): ดึงค่า sale_amount จากแถวถัดไป 1 แถว

บทสรุป: การประยุกต์ใช้ในงานจริง

การใช้ LEAD() และ LAG() ไม่ได้จำกัดอยู่แค่การเปรียบเทียบยอดขายเท่านั้น แต่ยังสามารถนำไปใช้ในการคำนวณอัตราการเปลี่ยนแปลง (Rate of Change), การหาความแตกต่างของสถานะ (State Transition) ในระบบ Workflow, หรือการวิเคราะห์ความแตกต่างของค่าทางสถิติระหว่างช่วงเวลาได้อย่างแม่นยำและมีประสิทธิภาพสูง การทำความเข้าใจ Window Functions เหล่านี้ถือเป็นทักษะสำคัญสำหรับ Data Engineer และ Data Analyst ระดับ Senior ที่ต้องการเขียน Query ที่ซับซ้อนและมีประสิทธิภาพใน PostgreSQL