การกำหนดเฟรมด้วย ROWS เทียบกับ RANGE
ความแตกต่างละเอียดอ่อนที่มักออกสอบระหว่างเฟรมตามแถวกับเฟรมตามค่า
การกำหนดเฟรมด้วย ROWS เทียบกับ RANGE เป็นบทเรียน SQL Interview Prep ฟรีบน CoddyKit นี่คือบทเรียนที่ 2 จากทั้งหมด 4 บทเรียน คุณสามารถอ่านบทเรียนทั้งหมดด้านล่างฟรี — จากนั้นลองปฏิบัติด้วยตัวคุณเองในเบราว์เซอร์พร้อมตัวแก้ไขโค้ดในตัวและติวเตอร์ AI ตลอด 24/7 บทเรียนนี้เป็นส่วนหนึ่งของเส้นทางการเรียน SQL Interview Prep และความก้าวหน้าของคุณจะซิงค์ข้ามเว็บและแอป CoddyKit คอร์ส SQL Interview Prep มีบทเรียนทั้งหมด 4 บทเรียน
ประเด็นความแตกต่างที่ผู้สัมภาษณ์ชอบถามเจาะลึก
เมื่อคุณเขียนยอดสะสมได้แล้ว คำถามต่อยอดตามธรรมชาติก็คือ "ROWS และ RANGE ในกรอบหน้าต่างแตกต่างกันอย่างไร" นี่เป็นสัญญาณวัดความเข้าใจระดับกลางที่ชัดเจน ผู้สมัครจำนวนมากใช้กรอบเป็นประจำทุกวันโดยไม่เคยสังเกตว่าคำสำคัญสองคำนี้ทำงานต่างกัน
ทั้งสองแบบกำหนดชุดแถวที่ฟังก์ชันรวมมองเห็นเหมือนกัน แต่ใช้วิธีนับชุดแถวนั้นแตกต่างกันโดยพื้นฐาน หากเข้าใจเรื่องนี้ได้ถูกต้อง คุณจะโดดเด่นขึ้น
ROWS นับแถวจริง
ROWS อิงตามตำแหน่ง ROWS BETWEEN 2 PRECEDING AND CURRENT ROW หมายความตามตัวอักษรว่าให้รวมแถวปัจจุบันกับแถวจริงสองแถวที่อยู่เหนือขึ้นไปโดยตรงในลำดับที่เรียงไว้
วิธีนี้ไม่สนใจว่าแถวข้างเคียงจะมีค่าของ ORDER BY เหมือนกันหรือไม่ สามแถวก็คือสามแถว ไม่มีเงื่อนไขเพิ่มเติม กรอบลักษณะนี้เป็นสิ่งที่คุณแทบจะต้องการเสมอสำหรับค่าเฉลี่ยเคลื่อนที่และยอดสะสมแบบเคร่งครัด
SELECT
sale_date,
amount,
SUM(amount) OVER (
ORDER BY sale_date
ROWS BETWEEN 2 PRECEDING AND CURRENT ROW
) AS rows_sum
FROM sales;RANGE นับตามค่า
RANGE อิงตามค่า โดยรวมทุกแถวที่ค่าของ ORDER BY อยู่ภายในช่วงเชิงตรรกะของค่าของแถวปัจจุบัน ไม่ใช่การนับจำนวนแถว
ผลที่สำคัญที่สุดคือ เมื่อใช้ RANGE แถวทั้งหมดที่มีค่า ORDER BY เสมอกันจะถูกถือเป็นกลุ่มเดียวกันของแถวที่มีค่าเท่ากัน ทุกแถวจะได้กรอบเดียวกัน และจึงได้ผลลัพธ์เดียวกัน
SELECT
sale_date,
amount,
SUM(amount) OVER (
ORDER BY sale_date
RANGE BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW
) AS range_sum
FROM sales;ตัวอย่างค่าเสมอที่แสดงความแตกต่าง
สมมติว่ามียอดขายสองรายการเกิดขึ้นในวันที่ 2024-03-02 โดยมีจำนวนเงิน 30 และ 40 และมีรายการวันที่ 2024-03-01 จำนวนเงิน 100 อยู่ก่อนหน้า
- เมื่อใช้ RANGE ถึง CURRENT ROW: แถวของวันที่ 03-02 ทั้งสองแถวอยู่ในกลุ่มเดียวกัน ดังนั้นทั้งคู่จะแสดง 100 + 30 + 40 = 170
- เมื่อใช้ ROWS ถึง CURRENT ROW: แถวของวันที่ 03-02 แถวแรกจะแสดง 130 ส่วนแถวที่สองจะแสดง 170 เพราะแต่ละแถวขยายกรอบออกไปทีละตำแหน่ง
ข้อมูลเดียวกัน แต่ได้ตัวเลขต่างกัน ความแตกต่างเมื่อค่าเสมอกันคือหัวใจของคำถามนี้
เหตุใดค่าเริ่มต้นจึงเป็น RANGE
โปรดจำไว้ว่า OVER (ORDER BY ...) ที่ไม่มีการระบุกรอบอย่างชัดเจน จะใช้ค่าเริ่มต้นเป็น RANGE BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW
นั่นหมายความว่ายอดสะสมแบบตรงไปตรงมาจะใช้ RANGE โดยไม่แจ้งให้ทราบ สำหรับคีย์การเรียงที่ไม่ซ้ำกัน ผลลัพธ์จะเหมือนกับ ROWS จึงทำให้ข้อผิดพลาดซ่อนอยู่ แต่ทันทีที่มีค่าการเรียงซ้ำ ยอดสะสมจะรวมแถวที่มีค่าเสมอกันเข้าเป็นกลุ่มเดียวกันอย่างเงียบ ๆ นี่คือเหตุผลที่วิศวกรผู้มีประสบการณ์ระบุ ROWS อย่างชัดเจน
RANGE พร้อมออฟเซ็ตตัวเลข
RANGE สามารถใช้ค่าออฟเซ็ตได้ ไม่ได้จำกัดแค่ UNBOUNDED เท่านั้น RANGE BETWEEN 7 PRECEDING AND CURRENT ROW เมื่อใช้กับคอลัมน์วันที่หรือตัวเลข จะรวมทุกแถวที่ค่าอยู่ภายในระยะ 7 หน่วยจากค่าปัจจุบัน
เมื่อใช้กับวันที่ จะได้กรอบข้อมูล "7 วันล่าสุด" อย่างแท้จริง ซึ่งข้ามวันที่หายไปได้อย่างถูกต้อง ขณะที่ ROWS 7 PRECEDING จะดึง แถว 7 แถวก่อนหน้าโดยไม่สนใจช่องว่าง การเข้าใจรายละเอียดนี้แสดงถึงความเข้าใจอย่างลึกซึ้งและเป็นคำตอบที่ดีมาก
SELECT
sale_date,
amount,
SUM(amount) OVER (
ORDER BY sale_date
RANGE BETWEEN INTERVAL '7 days' PRECEDING AND CURRENT ROW
) AS last_7_days
FROM sales;ROWS ไม่สนใจช่องว่าง
ในทางกลับกัน ROWS ไม่มีแนวคิดเรื่องช่องว่างของข้อมูล หากตารางยอดขายไม่มีข้อมูลในวันหยุดสุดสัปดาห์ ROWS BETWEEN 6 PRECEDING AND CURRENT ROW จะครอบคลุม 7 วันที่ บันทึกไว้ ซึ่งในความเป็นจริงอาจกินช่วงเวลาถึงสองสัปดาห์ตามปฏิทิน
ดังนั้นให้เลือกตามจุดประสงค์: ระเบียน N รายการล่าสุด หมายถึง ROWS ส่วน ค่าจำนวน N หน่วยล่าสุด (วัน ดอลลาร์) หมายถึง RANGE พร้อมออฟเซ็ต
ตรวจสอบการรองรับในแต่ละระบบฐานข้อมูล
คำตอบสัมภาษณ์ที่ตรงไปตรงมาควรกล่าวถึงข้อจำกัดด้านการรองรับ:
- PostgreSQL รองรับ
RANGEพร้อมออฟเซ็ตตั้งแต่รุ่น 11 และรองรับROWSอย่างเต็มรูปแบบ - เซิร์ฟเวอร์ SQL รองรับทั้ง
ROWSและRANGEแต่RANGEใช้ได้เฉพาะกับUNBOUNDED/CURRENT ROWไม่รองรับออฟเซ็ตตัวเลข - MySQL 8 รองรับทั้งสองแบบ แต่ชนิดของออฟเซ็ตสำหรับ
RANGEมีข้อจำกัด
หากไม่สามารถใช้ออฟเซ็ตตัวเลขของ RANGE ได้ คุณสามารถจำลองการทำงานด้วยการเชื่อมตารางเข้ากับตัวเองหรือสร้างปฏิทินขึ้นมา การกล่าวถึงประเด็นนี้แสดงว่าคุณเข้าใจการใช้งานจริง
GROUPS: โหมดที่สาม
ยังมีโหมดการกำหนดกรอบอีกแบบหนึ่งที่ไม่ค่อยมีใครพูดถึง นั่นคือ GROUPS ซึ่งนับ กลุ่มแถวที่มีค่าเท่ากัน แทนการนับแถวหรือค่า GROUPS BETWEEN 1 PRECEDING AND CURRENT ROW จะรวมกลุ่มแถวที่มีค่าเท่ากันของแถวปัจจุบันและกลุ่มก่อนหน้าอีกหนึ่งกลุ่ม
โดยทั่วไปไม่ค่อยจำเป็นต้องใช้ แต่การเอ่ยถึงโหมดนี้เมื่อถูกถามว่า "มีโหมดกรอบแบบอื่นอีกไหม" จะแสดงถึงความเข้าใจอย่างลึกซึ้ง มีการรองรับใน PostgreSQL 11 ขึ้นไปและระบบอื่นอีกเล็กน้อย
SELECT
sale_date,
amount,
SUM(amount) OVER (
ORDER BY sale_date
GROUPS BETWEEN 1 PRECEDING AND CURRENT ROW
) AS two_day_groups
FROM sales;กฎการตัดสินใจที่คุณท่องได้
สรุปหัวข้อนี้ให้เหลือเป็นประโยคเดียวที่คุณสามารถพูดในการสัมภาษณ์ได้:
"ใช้ ROWS เมื่อหมายถึงจำนวนแถวจริงที่ตายตัว ใช้ RANGE เมื่อหมายถึงช่วงเชิงตรรกะของค่าที่ใช้เรียงลำดับ และจำไว้ว่าค่าที่เสมอกันทำให้ผลลัพธ์ต่างกัน เพราะ RANGE แบบเริ่มต้นจะจัดกลุ่มค่าที่เท่ากันไว้ด้วยกัน"
ประโยคเดียวนี้ตอบคำถามได้ครบถ้วนและอย่างมั่นใจ
การเปรียบเทียบแบบเคียงข้างกัน
การใส่กรอบทั้งสองแบบไว้ในคำสั่งเดียวทำให้เห็นความแตกต่างอย่างชัดเจน เรียกใช้คำสั่งนี้กับข้อมูลที่มีวันที่ซ้ำ แล้วเปรียบเทียบสองคอลัมน์ทีละแถว
เมื่อวันที่ไม่ซ้ำกัน คอลัมน์ทั้งสองจะตรงกันทุกประการ แต่เมื่อวันที่มีค่าเท่ากัน คอลัมน์ RANGE จะแสดงผลรวมเดิมซ้ำในแถวที่มีค่าเท่ากัน ขณะที่คอลัมน์ ROWS จะเพิ่มขึ้นทีละขั้น
SELECT
sale_date,
amount,
SUM(amount) OVER (ORDER BY sale_date
ROWS BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW) AS rows_total,
SUM(amount) OVER (ORDER BY sale_date
RANGE BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW) AS range_total
FROM sales;ตรวจสอบอย่างรวดเร็ว
มีสองแถวที่มีค่าใน ORDER BY เท่ากันและใช้กรอบแบบเริ่มต้น จะเกิดอะไรขึ้น
สรุป: ROWS กับ RANGE
ROWS นับแถวจริง ส่วน RANGE นับตามค่าเชิงตรรกะของคอลัมน์ที่ใช้เรียงลำดับและจัดกลุ่มค่าที่เสมอกันเป็นแถวกลุ่มเดียวกัน กรอบเริ่มต้นของ OVER (ORDER BY ...) คือ RANGE จึงทำให้ผลรวมสะสมแบบง่าย ๆ อาจรวมค่าที่ใช้เรียงลำดับซ้ำไว้ด้วยกัน
เลือก ROWS สำหรับ "ระเบียน N รายการล่าสุด" และกรอบเคลื่อนที่ที่ไม่สนใจช่องว่าง เลือก RANGE พร้อมออฟเซ็ตสำหรับ "N วัน/ดอลลาร์ล่าสุด" ที่คำนึงถึงช่องว่าง การรู้ว่ามี GROUPS อยู่ด้วยถือเป็นข้อได้เปรียบ ต่อไปเราจะใช้การกำหนดกรอบแบบ ROWS เพื่อสร้างค่าเฉลี่ยเคลื่อนที่
เรียนรู้ SQL ด้วย AI tutor — ฟรี
เขียนและเรียกใช้โค้ดจริงในเบราว์เซอร์ของคุณ รับความช่วยเหลือทันทีจาก AI tutor 24/7 และเรียนรู้ต่อจากที่คุณหยุดบนเว็บหรือในแอป
- คอร์ส
- 30
- บทเรียน
- 120
คำถามที่พบบ่อย
บทเรียน “การกำหนดเฟรมด้วย ROWS เทียบกับ RANGE” ฟรีหรือไม่
ใช่ — ข้อความเต็มของ “การกำหนดเฟรมด้วย ROWS เทียบกับ RANGE” ฟรีให้อ่านที่นี่บนเว็บ เพื่อปฏิบัติแบบโต้ตอบ (ตัวแก้ไขโค้ดในตัวและติวเตอร์ AI ตลอด 24/7) และปลดล็อคส่วนที่เหลือของคอร์ส SQL Interview Prep ให้อัปเกรดเป็น CoddyKit PRO คอร์ส SQL Interview Prep มีบทเรียนทั้งหมด 4 บทเรียน
คุณจะเรียนรู้อะไรในบทเรียน “การกำหนดเฟรมด้วย ROWS เทียบกับ RANGE”
ความแตกต่างละเอียดอ่อนที่มักออกสอบระหว่างเฟรมตามแถวกับเฟรมตามค่า คุณปฏิบัติ SQL Interview Prep ด้วยโค้ดที่ใช้งานได้จริงที่คุณเรียกใช้โดยตรงในเบราว์เซอร์ และติวเตอร์ AI ตลอด 24/7 ตอบคำถามของคุณขณะที่คุณไปผ่านบทเรียน
คุณต้องมีประสบการณ์ก่อนที่จะเริ่มเรียน SQL Interview Prep หรือไม่
ไม่จำเป็นต้องมีประสบการณ์มาก่อน SQL Interview Prep บน CoddyKit ออกแบบมาสำหรับผู้เริ่มต้นไปจนถึงผู้เรียนขั้นสูง คุณสามารถเริ่มต้นที่นี่หรือเริ่มจากตัวแรกและเรียนด้วยความเร็วของคุณเอง นี่คือบทเรียนที่ 2 จากทั้งหมด 4 บทเรียน
บทเรียน “การกำหนดเฟรมด้วย ROWS เทียบกับ RANGE” ใช้เวลานานแค่ไหน
บทเรียน CoddyKit ส่วนใหญ่ใช้เวลาประมาณ 5–10 นาที แต่ละบทเรียนจึงสั้นและเป็นแบบโต้ตอบ คุณสามารถก้าวหน้าอย่างต่อเนื่องและกลับมาเรียนต่อจากตรงที่เพิ่งหยุดบนเว็บและแอปได้เลย
ฉันเขียนและรันโค้ดในบทเรียน SQL Interview Prep นี้ได้ไหม
ได้ บทเรียน SQL Interview Prep ทุกบทมีตัวแก้ไขโค้ดในตัว คุณจึงเขียนและรันโค้ดจริงได้เลยในเบราว์เซอร์ และได้รับข้อเสนอแนะจาก AI ในทันที — ไม่ต้องติดตั้งในเครื่องของคุณ
บทเรียนทั้งหมดในหลักสูตรนี้
- ผลรวมสะสมด้วยเฟรมวินโดว์
- การกำหนดเฟรมด้วย ROWS เทียบกับ RANGE
- ค่าเฉลี่ยเคลื่อนที่บนวินโดว์เลื่อน
- การแจกแจงสะสมและเปอร์เซ็นต์ของทั้งหมด