ช่วงต่อเนื่องที่ยังดำเนินอยู่จนถึงวันนี้
คำนวณช่วงต่อเนื่องที่กำลังดำเนินอยู่ และเริ่มนับใหม่เมื่อเกิดช่วงขาดตอน
ช่วงต่อเนื่องที่ยังดำเนินอยู่จนถึงวันนี้ เป็นบทเรียน SQL Interview Prep ฟรีบน CoddyKit นี่คือบทเรียนที่ 4 จากทั้งหมด 4 บทเรียน คุณสามารถอ่านบทเรียนทั้งหมดด้านล่างฟรี — จากนั้นลองปฏิบัติด้วยตัวคุณเองในเบราว์เซอร์พร้อมตัวแก้ไขโค้ดในตัวและติวเตอร์ AI ตลอด 24/7 บทเรียนนี้เป็นส่วนหนึ่งของเส้นทางการเรียน SQL Interview Prep และความก้าวหน้าของคุณจะซิงค์ข้ามเว็บและแอป CoddyKit คอร์ส SQL Interview Prep มีบทเรียนทั้งหมด 4 บทเรียน
คำถามเชิงผลิตภัณฑ์
ฟีเจอร์ช่วงต่อเนื่อง เช่น Duolingo หรือ Snapchat ต้องการช่วงต่อเนื่อง ปัจจุบัน ไม่ใช่ช่วงต่อเนื่องที่ยาวที่สุดในอดีต คำถามในการสัมภาษณ์คือ: "สำหรับผู้ใช้แต่ละคน พวกเขาใช้งานต่อเนื่องกันมากี่วันจนถึงวันนี้ หากวันนี้ไม่ได้ใช้งานให้เริ่มนับใหม่เป็น 0"
โจทย์นี้มีรายละเอียดเพิ่มเติมคือ ต้อง ยึดช่วงต่อเนื่องกับวันนี้ (หรือเมื่อวานภายใต้กฎผ่อนผัน) มาสร้างคำตอบโดยอาศัยพื้นฐานเรื่องช่องว่างและกลุ่มช่วงต่อเนื่องที่คุณรู้จักแล้ว
การนิยามการใช้งาน
ขั้นแรก ให้ยืนยันกติกากับผู้สัมภาษณ์ เพราะการตัดสินใจเหล่านี้เปลี่ยนคำสั่งสอบถามได้:
- ช่วงต่อเนื่องต้องมีกิจกรรม วันนี้ หรือยอมรับ เมื่อวาน ได้ (ช่วงผ่อนผัน)?
- เหตุการณ์หลายรายการในวันเดียวกันถูกรวมให้เหลือหนึ่งวันหรือไม่?
- เขตเวลาใดเป็นตัวกำหนดคำว่า "วัน"?
เราจะสมมติว่ามีหนึ่งแถวต่อวันที่มีการใช้งาน และช่วงต่อเนื่องยังเป็นปัจจุบันหากมีวันนี้ OR เมื่อวานรวมอยู่ด้วย
สร้างกลุ่มช่วงต่อเนื่องอีกครั้ง
นำจุดยึดเดิมกลับมาใช้: กำหนดหมายเลขให้วันของผู้ใช้แต่ละคนตามวันที่แล้วลบออก ทุกช่วงที่ต่อเนื่องกันจะมีจุดยึดเดียวกัน ช่วงต่อเนื่องปัจจุบันก็คือกลุ่มที่มี วันสุดท้ายเป็นวันนี้หรือเมื่อวาน
WITH numbered AS (
SELECT user_id, login_date,
ROW_NUMBER() OVER (
PARTITION BY user_id ORDER BY login_date
) AS rn
FROM logins
),
islands AS (
SELECT user_id,
MIN(login_date) AS streak_start,
MAX(login_date) AS streak_end,
COUNT(*) AS streak_len
FROM numbered
GROUP BY user_id, login_date - rn
)
SELECT * FROM islands;ระบุกลุ่มช่วงต่อเนื่องล่าสุด
กลุ่มช่วงต่อเนื่องล่าสุดของผู้ใช้แต่ละคนคือกลุ่มที่มีค่า streak_end มากที่สุด เราจะตรวจสอบว่าวันสิ้นสุดนั้นใหม่พอที่จะนับว่ายังดำเนินอยู่หรือไม่
CURRENT_DATE ให้ค่าวันนี้ ส่วน CURRENT_DATE - 1 คือเมื่อวาน หาก streak_end เท่ากับค่าใดค่าหนึ่ง ช่วงต่อเนื่องนั้นก็ยังใช้งานอยู่
WITH /* ...numbered, islands... */
latest AS (
SELECT *,
ROW_NUMBER() OVER (
PARTITION BY user_id ORDER BY streak_end DESC
) AS rn2
FROM islands
)
SELECT * FROM latest WHERE rn2 = 1;ตรวจสอบความเป็นปัจจุบัน
ตอนนี้ให้ตัดสินใจว่ากลุ่มช่วงต่อเนื่องล่าสุดยังใช้งานอยู่หรือไม่ หากวันที่สิ้นสุดเป็นวันนี้หรือเมื่อวาน ช่วงต่อเนื่องปัจจุบันจะมีค่าเท่ากับความยาวของกลุ่มนั้น มิฉะนั้นผู้ใช้ขาดช่วงต่อเนื่องแล้ว และค่าปัจจุบันจะเป็น 0
SELECT user_id,
CASE
WHEN streak_end >= CURRENT_DATE - 1
THEN streak_len
ELSE 0
END AS current_streak
FROM latest
WHERE rn2 = 1;คำสั่งสอบถามช่วงต่อเนื่องปัจจุบันฉบับเต็ม
ประกอบทุกขั้นตอนเข้าด้วยกัน: กำหนดหมายเลข สร้างกลุ่มช่วงต่อเนื่อง เลือกกลุ่มล่าสุดของผู้ใช้แต่ละคน แล้วใช้ CASE ตรวจสอบความเป็นปัจจุบัน นี่คือคำตอบฉบับสมบูรณ์
WITH numbered AS (
SELECT user_id, login_date,
ROW_NUMBER() OVER (
PARTITION BY user_id ORDER BY login_date
) AS rn
FROM logins
),
islands AS (
SELECT user_id,
MAX(login_date) AS streak_end,
COUNT(*) AS streak_len
FROM numbered
GROUP BY user_id, login_date - rn
),
latest AS (
SELECT *,
ROW_NUMBER() OVER (
PARTITION BY user_id ORDER BY streak_end DESC
) AS rn2
FROM islands
)
SELECT user_id,
CASE WHEN streak_end >= CURRENT_DATE - 1
THEN streak_len ELSE 0 END AS current_streak
FROM latest
WHERE rn2 = 1
ORDER BY user_id;ความเคร่งครัดแบบเฉพาะวันนี้
หากกฎทางธุรกิจเคร่งครัด — ช่วงต่อเนื่องจะยังใช้งานได้ เฉพาะเมื่อผู้ใช้มีการใช้งานวันนี้ — ให้เปลี่ยนการเปรียบเทียบเป็น streak_end = CURRENT_DATE
เวอร์ชันที่มีช่วงผ่อนผัน (>= CURRENT_DATE - 1) เป็นมิตรกว่าและพบได้บ่อยในแอปจริง เพราะวันนั้นอาจยังไม่สิ้นสุด ควรยืนยันเสมอว่าผู้สัมภาษณ์ต้องการแบบใด
CASE WHEN streak_end = CURRENT_DATE
THEN streak_len ELSE 0 END AS current_streakทางเลือก: ย้อนกลับไปตามลำดับ
กรอบความคิดอีกแบบที่ผู้สัมภาษณ์บางคนชอบคือ คำนวณระยะห่างจากแต่ละวันถึงวันนี้ วันหนึ่งจะเป็นส่วนหนึ่งของช่วงต่อเนื่องปัจจุบันก็ต่อเมื่อมีข้อมูลครบทุกวันตั้งแต่วันนั้นจนถึงวันนี้ หรือกล่าวอีกอย่างคือ เปรียบเทียบ login_date กับ CURRENT_DATE - (offset from the latest)
โดยทั่วไปวิธีกลุ่มช่วงต่อเนื่องจะกระชับกว่า แต่การรู้จักทางเลือกอื่นแสดงให้เห็นถึงความเข้าใจเชิงลึก แนวคิดสำคัญเหมือนกันคือห่วงโซ่ที่ไม่ขาดตอนและยึดกับวันนี้
การรวมผู้ใช้ที่ไม่ได้ใช้งาน
ผู้ใช้ที่ไม่อยู่ใน logins จะไม่มีกลุ่มช่วงต่อเนื่องและหายไป หากต้องรายงานช่วงต่อเนื่องของผู้ใช้ทุกคน (ซึ่งน่าจะเป็น 0) ให้ใช้ LEFT JOIN กับรายชื่อผู้ใช้ แล้วใช้ COALESCE เปลี่ยนผลลัพธ์เป็น 0
SELECT u.user_id,
COALESCE(s.current_streak, 0) AS current_streak
FROM users u
LEFT JOIN current_streaks s ON s.user_id = u.user_id;ข้อควรระวังเรื่องเขตเวลา
หากจัดเก็บกิจกรรมเป็นค่าประทับเวลา คำว่า "วันนี้" จะขึ้นอยู่กับเขตเวลา ต้องแปลงเขตเวลาก่อนตัดให้เหลือวันที่
- จัดเก็บและเปรียบเทียบใน UTC หรือแปลงเป็นเขตเวลาท้องถิ่นของผู้ใช้ก่อน
- ใช้
event_ts AT TIME ZONE 'UTC' AT TIME ZONE user_tzใน Postgres แล้วแปลงเป็นวันที่ - การใช้
::dateโดยไม่พิจารณาเขตเวลากับค่าประทับเวลา UTC อาจทำให้เหตุการณ์ช่วงค่ำไปอยู่ผิดวันตามปฏิทิน
การกล่าวถึงประเด็นนี้ช่วยป้องกันคำถามต่อยอดเกี่ยวกับข้อผิดพลาดคลาสสิกได้
SELECT user_id,
(event_ts AT TIME ZONE 'UTC'
AT TIME ZONE 'America/New_York')::date AS local_day
FROM events;ประสิทธิภาพและสรุปปิดท้าย
สำหรับแดชบอร์ดที่รีเฟรชบ่อย คำสั่งสอบถามนี้จะทำงานต่อผู้ใช้แต่ละคนโดยอ่านข้อมูลเพียงหนึ่งรอบ เพื่อให้ทำงานได้รวดเร็ว:
- สร้างดัชนีบน
(user_id, login_date) - อาจจำกัดข้อมูลนำเข้าให้เหลือเฉพาะวันที่ล่าสุด — ช่วงต่อเนื่องปัจจุบันไม่สามารถใช้ข้อมูลที่เก่ากว่าความยาวของช่วงเองได้ ดังนั้นใช้ช่วงข้อมูลย้อนหลัง เช่น 400 วันก็เพียงพอ
- สร้างข้อมูลรายวันเก็บไว้ในตารางช่วงต่อเนื่อง หากมีการอ่านข้อมูลบ่อยมาก
ตรวจสอบอย่างรวดเร็ว
ยืนยันว่าคุณเข้าใจจุดยึดที่อิงกับ "ปัจจุบัน"
สรุป
การคำนวณช่วงต่อเนื่องที่กำลังใช้งาน ณ วันนี้:
- สร้างกลุ่มช่วงต่อเนื่องด้วยจุดยึด
login_date - ROW_NUMBER() - เลือกกลุ่มล่าสุดของผู้ใช้แต่ละคนด้วยค่า
streak_endที่มากที่สุด - คืนค่าความยาวของกลุ่มก็ต่อเมื่อ
streak_endเป็นวันนี้ (หรือเมื่อวานสำหรับช่วงผ่อนผัน) มิฉะนั้นคืนค่า 0 - ใช้ LEFT JOIN กับ users เพื่อรวมบัญชีที่ไม่ได้ใช้งาน และจัดการเขตเวลาก่อนตัดให้เหลือวันที่
ตอนนี้คุณมีเครื่องมือครบชุดสำหรับการวิเคราะห์ช่วงต่อเนื่องแล้ว: การตรวจหาช่วงต่อเนื่อง ช่วงต่อเนื่องที่ยาวที่สุด เงื่อนไข N แถวต่อเนื่อง และช่วงต่อเนื่องที่ยังใช้งานอยู่
เรียนรู้ SQL ด้วย AI tutor — ฟรี
เขียนและเรียกใช้โค้ดจริงในเบราว์เซอร์ของคุณ รับความช่วยเหลือทันทีจาก AI tutor 24/7 และเรียนรู้ต่อจากที่คุณหยุดบนเว็บหรือในแอป
- คอร์ส
- 30
- บทเรียน
- 120
คำถามที่พบบ่อย
บทเรียน “ช่วงต่อเนื่องที่ยังดำเนินอยู่จนถึงวันนี้” ฟรีหรือไม่
ใช่ — ข้อความเต็มของ “ช่วงต่อเนื่องที่ยังดำเนินอยู่จนถึงวันนี้” ฟรีให้อ่านที่นี่บนเว็บ เพื่อปฏิบัติแบบโต้ตอบ (ตัวแก้ไขโค้ดในตัวและติวเตอร์ AI ตลอด 24/7) และปลดล็อคส่วนที่เหลือของคอร์ส SQL Interview Prep ให้อัปเกรดเป็น CoddyKit PRO คอร์ส SQL Interview Prep มีบทเรียนทั้งหมด 4 บทเรียน
คุณจะเรียนรู้อะไรในบทเรียน “ช่วงต่อเนื่องที่ยังดำเนินอยู่จนถึงวันนี้”
คำนวณช่วงต่อเนื่องที่กำลังดำเนินอยู่ และเริ่มนับใหม่เมื่อเกิดช่วงขาดตอน คุณปฏิบัติ SQL Interview Prep ด้วยโค้ดที่ใช้งานได้จริงที่คุณเรียกใช้โดยตรงในเบราว์เซอร์ และติวเตอร์ AI ตลอด 24/7 ตอบคำถามของคุณขณะที่คุณไปผ่านบทเรียน
คุณต้องมีประสบการณ์ก่อนที่จะเริ่มเรียน SQL Interview Prep หรือไม่
ไม่จำเป็นต้องมีประสบการณ์มาก่อน SQL Interview Prep บน CoddyKit ออกแบบมาสำหรับผู้เริ่มต้นไปจนถึงผู้เรียนขั้นสูง คุณสามารถเริ่มต้นที่นี่หรือเริ่มจากตัวแรกและเรียนด้วยความเร็วของคุณเอง นี่คือบทเรียนที่ 4 จากทั้งหมด 4 บทเรียน
บทเรียน “ช่วงต่อเนื่องที่ยังดำเนินอยู่จนถึงวันนี้” ใช้เวลานานแค่ไหน
บทเรียน CoddyKit ส่วนใหญ่ใช้เวลาประมาณ 5–10 นาที แต่ละบทเรียนจึงสั้นและเป็นแบบโต้ตอบ คุณสามารถก้าวหน้าอย่างต่อเนื่องและกลับมาเรียนต่อจากตรงที่เพิ่งหยุดบนเว็บและแอปได้เลย
ฉันเขียนและรันโค้ดในบทเรียน SQL Interview Prep นี้ได้ไหม
ได้ บทเรียน SQL Interview Prep ทุกบทมีตัวแก้ไขโค้ดในตัว คุณจึงเขียนและรันโค้ดจริงได้เลยในเบราว์เซอร์ และได้รับข้อเสนอแนะจาก AI ในทันที — ไม่ต้องติดตั้งในเครื่องของคุณ
บทเรียนทั้งหมดในหลักสูตรนี้
- ตรวจจับวันที่ในปฏิทินที่ต่อเนื่องกัน
- ช่วงต่อเนื่องที่ยาวที่สุดของผู้ใช้แต่ละคน
- แถวต่อเนื่อง N แถวที่ตรงตามเงื่อนไข
- ช่วงต่อเนื่องที่ยังดำเนินอยู่จนถึงวันนี้