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

แถวต่อเนื่อง N แถวที่ตรงตามเงื่อนไข

รูปแบบช่วงแบบคลาสสิก เช่น ยอดขายเกิน X เป็นเวลา 3 วันติดต่อกัน

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

โจทย์คลาสสิกของ LeetCode

นี่เป็นหนึ่งในโจทย์สัมภาษณ์ SQL ที่ถูกถามบ่อยที่สุด: "ค้นหาวันที่ทั้งหมดที่มี สามวันต่อเนื่องเป็นอย่างน้อย ซึ่งยอดขายสูงกว่าค่าขีดจำกัด" หรือโจทย์ยอดนิยมของ LeetCode ที่ให้ "รายงานสนามกีฬาที่มีแถวผู้เข้าชมอย่างน้อย 3 แถวต่อเนื่อง โดยแต่ละแถวมีจำนวนผู้เข้าชมมากกว่า 100 คน"

รูปแบบของโจทย์เหมือนกันเสมอ: แถวหนึ่งจะผ่านเกณฑ์ก็ต่อเมื่ออยู่ภายในช่วงของแถวที่ผ่านเกณฑ์ต่อเนื่องกัน N แถว บทเรียนนี้จะแสดงวิธีแก้ที่กระชับสองวิธี พร้อมกับกับดักที่ทำให้ผู้สมัครส่วนใหญ่ตอบผิด

ข้อมูลตัวอย่าง

เราจะใช้ตาราง sales รายวัน โดยมีเงื่อนไขเป็น amount > 100 เราต้องคืนค่าทุกวันที่อยู่ในช่วงของ วันตามปฏิทินที่ต่อเนื่องกันตั้งแต่ 3 วันขึ้นไป และทุกวันต้องตรงตามเงื่อนไข

  • sale_date — หนึ่งแถวต่อวัน
  • amount — ยอดขายรวมของวันนั้น

จุดละเอียดสำคัญคือ แถวต้องต่อเนื่องกันตาม ลำดับ และสำหรับรูปแบบที่อิงวันที่ แถวนั้นต้องต่อเนื่องกันตาม ปฏิทินด้วย

SELECT * FROM sales ORDER BY sale_date;
-- sale_date  | amount
-- 2024-03-01 |  120
-- 2024-03-02 |  150
-- 2024-03-03 |  130
-- 2024-03-04 |   90
-- 2024-03-05 |  200

แนวทางที่ 1: กรองแล้วจัดกลุ่มช่วงต่อเนื่อง

แนวทางที่เชื่อถือได้คือ เก็บเฉพาะแถวที่ตรงตามเงื่อนไขก่อน จากนั้นจัดกลุ่มแถวที่เหลือเป็นกลุ่มช่วงต่อเนื่อง แล้วเก็บเฉพาะกลุ่มที่มีความยาวอย่างน้อย N

ขั้นแรกคือการกรองด้วย WHERE ขั้นที่สองนำจุดยึดสำหรับปัญหาช่องว่างและกลุ่มช่วงต่อเนื่องกลับมาใช้ เนื่องจากเรากรองก่อน กลุ่มช่วงต่อเนื่องในที่นี้จึงหมายถึง "ช่วงของวันที่ต่อเนื่องกันและตรงตามเงื่อนไข"

WITH qualifying AS (
  SELECT sale_date
  FROM sales
  WHERE amount > 100
)
SELECT * FROM qualifying ORDER BY sale_date;

การกำหนดจุดยึดให้ช่วงที่ตรงตามเงื่อนไข

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

WITH qualifying AS (
  SELECT sale_date
  FROM sales
  WHERE amount > 100
),
numbered AS (
  SELECT sale_date,
    ROW_NUMBER() OVER (ORDER BY sale_date) AS rn
  FROM qualifying
)
SELECT sale_date, sale_date - rn AS grp
FROM numbered;

การเก็บกลุ่มที่ยาวเพียงพอ

จัดกลุ่มตามจุดยึด นับจำนวนแถว แล้วเก็บเฉพาะกลุ่มที่มี COUNT(*) >= 3 หากผู้สัมภาษณ์ต้องการวันที่ที่ตรงตามเงื่อนไขแต่ละวันกลับมา ให้เชื่อมจุดยึดที่เก็บไว้เข้ากับแถวที่มีหมายเลข

WITH qualifying AS (
  SELECT sale_date FROM sales WHERE amount > 100
),
numbered AS (
  SELECT sale_date,
    ROW_NUMBER() OVER (ORDER BY sale_date) AS rn
  FROM qualifying
),
islands AS (
  SELECT sale_date - rn AS grp, COUNT(*) AS len
  FROM numbered
  GROUP BY sale_date - rn
  HAVING COUNT(*) >= 3
)
SELECT n.sale_date
FROM numbered n
JOIN islands i ON n.sale_date - n.rn = i.grp
ORDER BY n.sale_date;

แนวทางที่ 2: หน้าต่าง COUNT แบบเลื่อน

แนวทางที่กระชับกว่าเมื่อ N มีค่าต่ำและกำหนดตายตัว คือใช้กรอบหน้าต่างเพื่อนับว่ามีแถวรอบข้างกี่แถวที่ตรงตามเงื่อนไข หากหน้าต่างใดที่มี N แถวต่อเนื่องและรวมแถวนี้มีทุกแถวตรงตามเงื่อนไข แถวนั้นก็อยู่ในผลลัพธ์

ขั้นแรกให้เพิ่มเครื่องหมายบูลีน จากนั้นหาผลรวมของเครื่องหมายนั้นบนกรอบหน้าต่างแบบเลื่อน

SELECT sale_date, amount,
  CASE WHEN amount > 100 THEN 1 ELSE 0 END AS ok
FROM sales;

การหาผลรวมบนกรอบสามแบบ

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

นี่คือเทคนิคที่อยู่เบื้องหลังคำตอบของ LeetCode 601 (การจราจรมนุษย์ในสนามกีฬา)

WITH flagged AS (
  SELECT sale_date, amount,
    CASE WHEN amount > 100 THEN 1 ELSE 0 END AS ok
  FROM sales
),
w AS (
  SELECT *,
    SUM(ok) OVER (ORDER BY sale_date
      ROWS BETWEEN 2 PRECEDING AND CURRENT ROW) AS s_end,
    SUM(ok) OVER (ORDER BY sale_date
      ROWS BETWEEN 1 PRECEDING AND 1 FOLLOWING) AS s_mid,
    SUM(ok) OVER (ORDER BY sale_date
      ROWS BETWEEN CURRENT ROW AND 2 FOLLOWING) AS s_start
  FROM flagged
)
SELECT sale_date, amount
FROM w
WHERE ok = 1 AND (s_end = 3 OR s_mid = 3 OR s_start = 3);

กับดักเรื่องช่องว่างของปฏิทิน

แนวทางผลรวมบนหน้าต่างใช้ ROWS ซึ่งนับแถวผลลัพธ์ที่อยู่ติดกัน ไม่ใช่วันที่ตามปฏิทินที่อยู่ติดกัน หากกรองวันที่ไม่ตรงตามเงื่อนไขออกไปแล้ว แถวสองแถวอาจอยู่ติดกันในผลลัพธ์ แต่ไม่ใช่วันที่ต่อเนื่องกันตามปฏิทิน

บทเรียน: ใช้หน้าต่างแบบเลื่อนกับชุดข้อมูลรายวันทั้งหมด (อย่ากรองล่วงหน้า) หรือใช้วิธีจุดยึดวันที่ซึ่งคำนึงถึงช่องว่างของปฏิทินโดยธรรมชาติ ควรอธิบายข้อแลกเปลี่ยนนี้ในการสัมภาษณ์

การทำให้ใช้ได้กับ N ใด ๆ

แนวทางที่ 1 (กรองแล้วจัดกลุ่มช่วงต่อเนื่อง) ทำให้ใช้ได้ทั่วไปอย่างง่ายดาย เพียงเปลี่ยน HAVING COUNT(*) >= N นี่คือข้อได้เปรียบสำคัญเหนือผลรวมจากหน้าต่างหลายชุด ซึ่งต้องเพิ่มกรอบหน้าต่างเมื่อ N มีค่ามากขึ้น

สำหรับ N ที่รับเป็นพารามิเตอร์หรือมีค่ามาก ควรเลือกวิธีกลุ่มช่วงต่อเนื่อง เพราะเปลี่ยนเพียงค่าขีดจำกัดเดียว แทนที่จะต้องเขียนหน้าต่างด้วยตนเองจำนวน N−1 ชุด

-- only the threshold changes for N = 5
HAVING COUNT(*) >= 5

การเลือกแนวทาง

แนวทางตัดสินใจสั้น ๆ สำหรับอธิบายด้วยวาจา:

  • กรองแล้วจัดกลุ่มช่วงต่อเนื่อง: คำนึงถึงช่องว่างของปฏิทิน ใช้ได้กับ N ใด ๆ และคืนค่าช่วงต่อเนื่องทั้งหมด — เป็นค่าเริ่มต้นที่ปลอดภัย
  • ผลรวมของหน้าต่างแบบเลื่อน: สวยงามสำหรับ N ขนาดเล็กที่กำหนดตายตัวบนชุดข้อมูลรายวันที่หนาแน่น แต่ต้องระวังกับดักระหว่าง ROWS กับปฏิทิน

การกล่าวถึงทั้งสองวิธีแล้วให้เหตุผลประกอบว่าเลือกวิธีใด คือสิ่งที่ผู้สัมภาษณ์ระดับกลางถึงอาวุโสให้คุณค่าอย่างแท้จริง

คำตอบฉบับเต็ม

คำตอบที่ใช้ได้กับระบบต่าง ๆ และ N ใด ๆ ซึ่งคำนึงถึงความต่อเนื่องตามปฏิทินและคืนค่าวันที่ที่ตรงตามเงื่อนไข:

WITH qualifying AS (
  SELECT sale_date FROM sales WHERE amount > 100
),
numbered AS (
  SELECT sale_date,
    ROW_NUMBER() OVER (ORDER BY sale_date) AS rn
  FROM qualifying
),
islands AS (
  SELECT sale_date - rn AS grp, COUNT(*) AS len
  FROM numbered
  GROUP BY sale_date - rn
  HAVING COUNT(*) >= 3
)
SELECT n.sale_date
FROM numbered n
JOIN islands i ON n.sale_date - n.rn = i.grp
ORDER BY n.sale_date;

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

ค้นหาจุดผิดพลาดเล็กน้อยที่ซ่อนอยู่

สรุป

สำหรับ N แถวต่อเนื่องที่ตรงตามเงื่อนไข:

  • กรองแล้วจัดกลุ่มช่วงต่อเนื่อง: เก็บแถวที่ตรงตามเงื่อนไข ใช้จุดยึดด้วย date - ROW_NUMBER() จัดกลุ่ม และใช้ HAVING COUNT(*) >= N วิธีนี้ใช้ได้กับ N ใด ๆ และคำนึงถึงช่องว่างของปฏิทิน
  • ผลรวมของหน้าต่างแบบเลื่อน: ทำเครื่องหมายแถว แล้วหาผลรวมบนกรอบหน้าต่าง N แถวที่กำหนดตายตัว วิธีนี้กระชับ แต่ต้องระวังความแตกต่างระหว่าง ROWS กับปฏิทินเมื่อใช้กับข้อมูลที่กรองล่วงหน้า

ถัดไป: การคำนวณช่วงต่อเนื่องที่กำลังใช้งานของผู้ใช้ ณ วันนี้

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

บทเรียน “แถวต่อเนื่อง N แถวที่ตรงตามเงื่อนไข” ฟรีหรือไม่

ใช่ — ข้อความเต็มของ “แถวต่อเนื่อง N แถวที่ตรงตามเงื่อนไข” ฟรีให้อ่านที่นี่บนเว็บ เพื่อปฏิบัติแบบโต้ตอบ (ตัวแก้ไขโค้ดในตัวและติวเตอร์ AI ตลอด 24/7) และปลดล็อคส่วนที่เหลือของคอร์ส SQL Interview Prep ให้อัปเกรดเป็น CoddyKit PRO คอร์ส SQL Interview Prep มีบทเรียนทั้งหมด 4 บทเรียน

คุณจะเรียนรู้อะไรในบทเรียน “แถวต่อเนื่อง N แถวที่ตรงตามเงื่อนไข”

รูปแบบช่วงแบบคลาสสิก เช่น ยอดขายเกิน X เป็นเวลา 3 วันติดต่อกัน คุณปฏิบัติ SQL Interview Prep ด้วยโค้ดที่ใช้งานได้จริงที่คุณเรียกใช้โดยตรงในเบราว์เซอร์ และติวเตอร์ AI ตลอด 24/7 ตอบคำถามของคุณขณะที่คุณไปผ่านบทเรียน

คุณต้องมีประสบการณ์ก่อนที่จะเริ่มเรียน SQL Interview Prep หรือไม่

ไม่จำเป็นต้องมีประสบการณ์มาก่อน SQL Interview Prep บน CoddyKit ออกแบบมาสำหรับผู้เริ่มต้นไปจนถึงผู้เรียนขั้นสูง คุณสามารถเริ่มต้นที่นี่หรือเริ่มจากตัวแรกและเรียนด้วยความเร็วของคุณเอง นี่คือบทเรียนที่ 3 จากทั้งหมด 4 บทเรียน

บทเรียน “แถวต่อเนื่อง N แถวที่ตรงตามเงื่อนไข” ใช้เวลานานแค่ไหน

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

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

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

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

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