0Pricing
SQL Interview Prep · บทเรียน

ช่วงต่อเนื่องที่ยาวที่สุดของผู้ใช้แต่ละคน

คำนวณความยาวสูงสุดของช่วงที่เกิดขึ้นต่อเนื่องภายในแต่ละกลุ่ม

ช่วงต่อเนื่องที่ยาวที่สุดของผู้ใช้แต่ละคน เป็นบทเรียน SQL Interview Prep ฟรีบน CoddyKit นี่คือบทเรียนที่ 2 จากทั้งหมด 4 บทเรียน คุณสามารถอ่านบทเรียนทั้งหมดด้านล่างฟรี — จากนั้นลองปฏิบัติด้วยตัวคุณเองในเบราว์เซอร์พร้อมตัวแก้ไขโค้ดในตัวและติวเตอร์ AI ตลอด 24/7 บทเรียนนี้เป็นส่วนหนึ่งของเส้นทางการเรียน SQL Interview Prep และความก้าวหน้าของคุณจะซิงค์ข้ามเว็บและแอป CoddyKit คอร์ส SQL Interview Prep มีบทเรียนทั้งหมด 4 บทเรียน

คำถาม

คำถามต่อยอดที่พบบ่อยหลังการตรวจหาช่วงวันที่ต่อเนื่องคือ "สำหรับผู้ใช้แต่ละราย ช่วงวันที่ผู้ใช้นั้นใช้งานต่อเนื่องกัน ยาวที่สุด คือช่วงใด" ทีมผลิตภัณฑ์และทีมการเติบโตมักถามคำถามนี้เพื่อวัดการมีส่วนร่วม

คุณรู้วิธีระบุช่วงต่อเนื่องแต่ละช่วงอยู่แล้ว ขั้นตอนใหม่คือการหาความยาวสูงสุดของช่วงต่อเนื่อง สำหรับผู้ใช้แต่ละราย และบ่อยครั้งยังต้องแสดงวันที่ของช่วงต่อเนื่องที่ดีที่สุดด้วย บทเรียนนี้ต่อยอดโดยตรงจากโครงร่างช่องว่างและกลุ่มช่วงต่อเนื่อง

ทบทวนการสร้างกลุ่มช่วงต่อเนื่อง

จากบทเรียนก่อนหน้า การจัดกลุ่มแต่ละช่วงใช้ login_date - ROW_NUMBER() เป็นค่าอ้างอิงของกลุ่มช่วงต่อเนื่อง ผู้ใช้แต่ละรายอาจมีหลายกลุ่มช่วงต่อเนื่อง เราจะคำนวณให้ได้หนึ่งแถวต่อหนึ่งกลุ่มก่อน แล้วจึงลดผลลัพธ์ให้เหลือหนึ่งแถวต่อผู้ใช้

โปรดจำแผนสองชั้นนี้ไว้: ขั้นแรกสร้างกลุ่มช่วงต่อเนื่อง จากนั้นจึงรวมกลุ่มช่วงต่อเนื่องเหล่านั้น

WITH numbered AS (
  SELECT user_id, login_date,
    ROW_NUMBER() OVER (
      PARTITION BY user_id ORDER BY login_date
    ) AS rn
  FROM logins
)
SELECT user_id, login_date - rn AS grp
FROM numbered;

หนึ่งแถวต่อหนึ่งกลุ่มช่วงต่อเนื่อง

รวมแต่ละกลุ่มช่วงต่อเนื่องให้เหลือแถวสรุปเดียว ซึ่งมีความยาวและช่วงวันที่ของกลุ่มนั้น จัดกลุ่มตามผู้ใช้และค่าอ้างอิง แล้วคำนวณตัวชี้วัด

เราตั้งชื่อ CTE นี้ว่า islands เพื่อให้ชั้นถัดไปอ่านข้อมูลได้อย่างเป็นระเบียบ

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;

คำตอบแบบง่าย: ความยาวสูงสุด

หากผู้สัมภาษณ์ต้องการเพียงความยาว ขั้นตอนสุดท้ายมีเพียงบรรทัดเดียว: จัดกลุ่มกลุ่มช่วงต่อเนื่องตามผู้ใช้ แล้วหาความยาวสูงสุด

นี่คือคำตอบที่กระชับที่สุดเมื่อไม่จำเป็นต้องแสดงวันที่เริ่มต้นและวันที่สิ้นสุด

-- ...numbered and islands CTEs as before...
SELECT
  user_id,
  MAX(streak_len) AS longest_streak
FROM islands
GROUP BY user_id
ORDER BY user_id;

แสดงวันที่ร่วมด้วย

บ่อยครั้งผู้สัมภาษณ์จะถามต่อว่า "และแสดงด้วยว่าช่วงต่อเนื่องนั้นเกิดขึ้นเมื่อใด" การใช้ MAX เพียงอย่างเดียวไม่สามารถบอกได้ว่ากลุ่มช่วงต่อเนื่องใดเป็นผู้ชนะ คุณต้อง จัดอันดับกลุ่มช่วงต่อเนื่องภายในผู้ใช้แต่ละราย แล้วเก็บอันดับที่ 1

ใช้ ROW_NUMBER โดยเรียงตามความยาวจากมากไปน้อย เพื่อให้ช่วงต่อเนื่องที่ดีที่สุดของผู้ใช้แต่ละรายได้อันดับที่ 1 เพิ่มเกณฑ์ตัดสินกรณีเสมอเพื่อให้ผลลัพธ์ถูกกำหนดอย่างแน่นอน

ROW_NUMBER() OVER (
  PARTITION BY user_id
  ORDER BY streak_len DESC, streak_start ASC
) AS rnk

จัดอันดับและกรอง

ห่อการจัดอันดับไว้ใน CTE แล้วกรองให้เหลือ rnk = 1 คุณไม่สามารถกรองฟังก์ชันหน้าต่างโดยตรงใน WHERE ได้ ดังนั้นจึงจำเป็นต้องมีชั้นเพิ่มเติม

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
),
ranked AS (
  SELECT *,
    ROW_NUMBER() OVER (
      PARTITION BY user_id
      ORDER BY streak_len DESC, streak_start
    ) AS rnk
  FROM islands
)
SELECT user_id, streak_start, streak_end, streak_len
FROM ranked
WHERE rnk = 1;

RANK เทียบกับ ROW_NUMBER เมื่อเสมอกัน

ถ้าผู้ใช้รายหนึ่งมีช่วงต่อเนื่องที่ยาวที่สุดเท่ากันสองช่วง และผู้สัมภาษณ์ต้องการให้แสดง ทั้งสองช่วง จะทำอย่างไร ให้เปลี่ยน ROW_NUMBER เป็น RANK แล้วเก็บ rnk = 1

  • ROW_NUMBER — มีผู้ชนะเพียงหนึ่งช่วงต่อผู้ใช้ (ผลลัพธ์กรณีเสมอจะไม่แน่นอนหากไม่เพิ่มเกณฑ์ตัดสิน)
  • RANK — ช่วงต่อเนื่องที่ยาวที่สุดและเสมอกันทั้งหมดจะได้อันดับที่ 1 และถูกเก็บไว้ทั้งหมด

ระบุให้ชัดว่าผู้สัมภาษณ์ต้องการพฤติกรรมแบบใด เพราะแสดงให้เห็นว่าคุณใส่ใจกับกรณีขอบ

RANK() OVER (
  PARTITION BY user_id
  ORDER BY streak_len DESC
) AS rnk  -- keep all rnk = 1

ตัวอย่างที่ทำให้ดู

สมมติว่าผู้ใช้ 7 เข้าสู่ระบบวันที่ 1-4 มกราคม จากนั้นวันที่ 10-11 มกราคม แล้วจึงวันที่ 20-23 มกราคม จะมีกลุ่มช่วงต่อเนื่องสามกลุ่มที่มีความยาว 4, 2 และ 4 วัน ความยาวสูงสุดคือ 4 วัน และมีช่วงที่เสมอกัน

  • เมื่อใช้ ROW_NUMBER ร่วมกับเกณฑ์ตัดสิน streak_start: จะแสดงเฉพาะช่วงวันที่ 1-4 มกราคม
  • เมื่อใช้ RANK: จะแสดงทั้งช่วงวันที่ 1-4 มกราคมและช่วงวันที่ 20-23 มกราคม

การกล่าวประเด็นนี้ออกมาแสดงให้เห็นว่าคุณได้พิจารณาเรื่องรายการซ้ำแล้ว

การจัดการผู้ใช้ที่ไม่เคยเข้าสู่ระบบ

ผู้สัมภาษณ์อาจถามว่า: "แล้วผู้ใช้ที่ไม่เคยเข้าสู่ระบบเลยล่ะ?" ผู้ใช้เหล่านั้นไม่มีแถวใน logins จึงหายไปจากผลลัพธ์ หากต้องแสดงผู้ใช้เหล่านั้นพร้อมช่วงต่อเนื่องเป็น 0 ให้ใช้ LEFT JOIN กับตาราง users ทั้งตาราง และใช้ COALESCE

SELECT u.user_id,
  COALESCE(MAX(i.streak_len), 0) AS longest_streak
FROM users u
LEFT JOIN islands i ON i.user_id = u.user_id
GROUP BY u.user_id;

หมายเหตุด้านประสิทธิภาพ

รูปแบบนี้อ่านข้อมูลตามลำดับหนึ่งรอบ แล้วจัดกลุ่มอีกหนึ่งครั้ง เพื่อให้ทำงานได้รวดเร็ว:

  • ตรวจสอบให้มีดัชนีบน (user_id, login_date) เพื่อให้ ORDER BY ของหน้าต่างไม่ต้องเรียงลำดับใหม่
  • กำจัดข้อมูลซ้ำตั้งแต่ต้น หากแหล่งข้อมูลมีเหตุการณ์หลายรายการต่อวัน
  • หลีกเลี่ยงการครอบ login_date ด้วยฟังก์ชันใน ORDER BY เพราะอาจทำให้ใช้ดัชนีไม่ได้

สำหรับตารางขนาดใหญ่มาก วิธีนี้ทำงานได้เร็วกว่าวิธีเชื่อมตารางกับตัวเองอย่างชัดเจน

คำตอบฉบับเต็มสำหรับการสัมภาษณ์

นี่คือคำสั่งสอบถามฉบับสมบูรณ์และเรียบเรียงอย่างดี ซึ่งคืนค่าช่วงต่อเนื่องที่ยาวที่สุดของผู้ใช้แต่ละคนพร้อมวันที่ของช่วงนั้น — เป็นเวอร์ชันที่ควรเขียนบนกระดาน

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
),
ranked AS (
  SELECT *,
    ROW_NUMBER() OVER (
      PARTITION BY user_id
      ORDER BY streak_len DESC, streak_start
    ) AS rnk
  FROM islands
)
SELECT user_id, streak_start, streak_end, streak_len
FROM ranked
WHERE rnk = 1
ORDER BY user_id;

ตรวจสอบอย่างรวดเร็ว

เลือกเครื่องมือที่เหมาะสมกับข้อกำหนด

สรุป

การคำนวณช่วงต่อเนื่องที่ยาวที่สุดของผู้ใช้แต่ละคน:

  • สร้างกลุ่มช่วงต่อเนื่องด้วยจุดยึด login_date - ROW_NUMBER()
  • ยุบแต่ละกลุ่มให้เหลือความยาวและช่วงวันที่
  • หากต้องการเฉพาะความยาว ให้จัดกลุ่มตามผู้ใช้แล้วใช้ MAX(streak_len)
  • หากต้องการวันที่ด้วย ให้จัดอันดับกลุ่มช่วงต่อเนื่องภายในผู้ใช้แต่ละคน แล้วเก็บอันดับที่ 1 — ใช้ RANK เพื่อรวมกรณีที่เสมอกัน และใช้ ROW_NUMBER เมื่อต้องการผู้ชนะเพียงหนึ่งราย
  • ใช้ LEFT JOIN กับ users เพื่อแสดงผู้ใช้ที่มีช่วงต่อเนื่องเป็นศูนย์

ถัดไป: การตรวจหาจำนวนแถวต่อเนื่อง N แถวที่ตรงตามเงื่อนไข

คำถามที่พบบ่อย

บทเรียน “ช่วงต่อเนื่องที่ยาวที่สุดของผู้ใช้แต่ละคน” ฟรีหรือไม่

ใช่ — ข้อความเต็มของ “ช่วงต่อเนื่องที่ยาวที่สุดของผู้ใช้แต่ละคน” ฟรีให้อ่านที่นี่บนเว็บ เพื่อปฏิบัติแบบโต้ตอบ (ตัวแก้ไขโค้ดในตัวและติวเตอร์ 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 ออกแบบมาสำหรับผู้เริ่มต้นไปจนถึงผู้เรียนขั้นสูง คุณสามารถเริ่มต้นที่นี่หรือเริ่มจากตัวแรกและเรียนด้วยความเร็วของคุณเอง นี่คือบทเรียนที่ 2 จากทั้งหมด 4 บทเรียน

บทเรียน “ช่วงต่อเนื่องที่ยาวที่สุดของผู้ใช้แต่ละคน” ใช้เวลานานแค่ไหน

บทเรียน CoddyKit ส่วนใหญ่ใช้เวลาประมาณ 5–10 นาที แต่ละบทเรียนจึงสั้นและเป็นแบบโต้ตอบ คุณสามารถก้าวหน้าอย่างต่อเนื่องและกลับมาเรียนต่อจากตรงที่เพิ่งหยุดบนเว็บและแอปได้เลย

ฉันเขียนและรันโค้ดในบทเรียน SQL Interview Prep นี้ได้ไหม

ได้ บทเรียน SQL Interview Prep ทุกบทมีตัวแก้ไขโค้ดในตัว คุณจึงเขียนและรันโค้ดจริงได้เลยในเบราว์เซอร์ และได้รับข้อเสนอแนะจาก AI ในทันที — ไม่ต้องติดตั้งในเครื่องของคุณ

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

  1. ตรวจจับวันที่ในปฏิทินที่ต่อเนื่องกัน
  2. ช่วงต่อเนื่องที่ยาวที่สุดของผู้ใช้แต่ละคน
  3. แถวต่อเนื่อง N แถวที่ตรงตามเงื่อนไข
  4. ช่วงต่อเนื่องที่ยังดำเนินอยู่จนถึงวันนี้
← กลับไปที่ SQL Interview Prep