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

ชุดโจทย์สัมภาษณ์จำลองฉบับเต็ม

โจทย์ครบกระบวนการแบบจับเวลา ซึ่งผสานการเชื่อมตาราง ฟังก์ชันหน้าต่าง และ CTE ภายใต้เงื่อนไขการสัมภาษณ์

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

ลำดับการดำเนินของรอบสัมภาษณ์ SQL

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

  • ทวนโจทย์ และยืนยันสคีมา
  • ขอความชัดเจนเกี่ยวกับกรณีขอบ (ค่า NULL ค่าที่เท่ากัน ข้อมูลซ้ำ) ก่อนเขียนคำสั่ง
  • อธิบายแนวทาง จากนั้นจึงเขียนคำสั่งสืบค้น
  • ทดสอบ กับตัวอย่างขนาดเล็กในใจ

ผู้สัมภาษณ์ให้คะแนนกระบวนการของคุณมากพอ ๆ กับคำสั่งสืบค้นสุดท้าย

สคีมาร่วม

โจทย์ทั้งหมดด้านล่างใช้สคีมาอีคอมเมิร์ซขนาดเล็กนี้ โปรดอ่านไว้ครั้งเดียวเพื่อให้เข้าใจคำสั่งสืบค้นแต่ละข้อ

  • customers(id, name, country)
  • orders(id, customer_id, order_date, status, amount)
  • order_items(order_id, product_id, quantity)
  • products(id, name, category, price)

จดจำสคีมานี้ไว้ เพราะส่วนที่เหลือของบทเรียนจะอ้างอิงถึงตารางเหล่านี้

-- orders.status is one of: 'paid','pending','cancelled'
-- amount is the order total in the customer's currency

โจทย์ที่ 1: ลูกค้าที่มียอดใช้จ่ายสูงสุด

“แสดงลูกค้า 3 อันดับแรกตามยอดใช้จ่ายที่ชำระแล้วทั้งหมด พร้อมชื่อและยอดรวม”

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

SELECT c.name,
       SUM(o.amount) AS total_spend
FROM customers c
JOIN orders o ON o.customer_id = c.id
WHERE o.status = 'paid'
GROUP BY c.id, c.name
ORDER BY total_spend DESC
LIMIT 3;

โจทย์ที่ 2: ลูกค้าที่ไม่เคยสั่งซื้อ

“แสดงรายชื่อลูกค้าที่ไม่เคยสั่งซื้อเลย” นี่คือรูปแบบการเชื่อมเพื่อค้นหารายการที่ไม่ตรงกัน วิธีแก้ที่ชัดเจนมีสองแบบ: LEFT JOIN ร่วมกับ IS NULL หรือ NOT EXISTS

ควรเลือก NOT EXISTS เพราะปลอดภัยต่อค่า NULL (ต่างจาก NOT IN) ควรกล่าวถึงความแตกต่างนี้ เพราะนี่คือสิ่งที่ผู้สัมภาษณ์ต้องการดูว่าคุณเข้าใจหรือไม่

-- NULL-safe anti-join
SELECT c.id, c.name
FROM customers c
WHERE NOT EXISTS (
  SELECT 1
  FROM orders o
  WHERE o.customer_id = c.id
);

โจทย์ที่ 3: จำนวนเงินคำสั่งซื้อสูงเป็นอันดับสอง

“ค้นหาจำนวนเงินคำสั่งซื้อที่แตกต่างกันและสูงเป็นอันดับสอง” วิธีที่สะอาดที่สุดและไม่ถูกรบกวนจากค่าที่เท่ากันคือใช้ DENSE_RANK เพื่อให้จำนวนเงินที่ซ้ำกันมีอันดับเดียวกัน

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

SELECT amount
FROM (
  SELECT amount,
         DENSE_RANK() OVER (ORDER BY amount DESC) AS rnk
  FROM orders
) ranked
WHERE rnk = 2;

โจทย์ที่ 4: คำสั่งซื้อล่าสุดของลูกค้าแต่ละราย

“แสดงคำสั่งซื้อล่าสุดของลูกค้าแต่ละราย” นี่คือรูปแบบการเก็บแถวล่าสุดของแต่ละคีย์ โดยใช้ ROW_NUMBER แบ่งกลุ่มตามลูกค้าและเรียงตามวันที่จากใหม่ไปเก่า

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

SELECT customer_id, id AS order_id, order_date, amount
FROM (
  SELECT o.*,
         ROW_NUMBER() OVER (
           PARTITION BY customer_id
           ORDER BY order_date DESC, id DESC
         ) AS rn
  FROM orders o
) t
WHERE rn = 1;

โจทย์ที่ 5: การเติบโตเทียบเดือนก่อน

“คำนวณรายได้ที่ชำระแล้วรายเดือนและเปอร์เซ็นต์การเปลี่ยนแปลงเมื่อเทียบกับเดือนก่อน” โจทย์นี้ผสานการรวมยอดใน CTE เข้ากับ LAG

ขั้นแรกให้รวมยอดตามเดือน ขั้นที่สองให้เปรียบเทียบแต่ละเดือนกับเดือนก่อนหน้าโดยใช้ LAG ต้องป้องกันการหารเพื่อไม่ให้เดือนแรก (ซึ่งไม่มีเดือนก่อนหน้า) เกิดข้อผิดพลาด

WITH monthly AS (
  SELECT DATE_TRUNC('month', order_date) AS mth,
         SUM(amount) AS revenue
  FROM orders
  WHERE status = 'paid'
  GROUP BY DATE_TRUNC('month', order_date)
)
SELECT mth,
       revenue,
       LAG(revenue) OVER (ORDER BY mth) AS prev_revenue,
       ROUND(
         100.0 * (revenue - LAG(revenue) OVER (ORDER BY mth))
         / NULLIF(LAG(revenue) OVER (ORDER BY mth), 0), 2
       ) AS pct_change
FROM monthly
ORDER BY mth;

โจทย์ที่ 6: สินค้าอันดับหนึ่งของแต่ละหมวดหมู่

“สำหรับแต่ละหมวดหมู่ ให้แสดงสินค้าที่ขายดีที่สุดตามจำนวนรวม” นี่คือรูปแบบ N อันดับแรกของแต่ละกลุ่ม: รวมยอด จัดอันดับภายในแต่ละกลุ่มย่อย แล้วกรองเฉพาะอันดับ 1

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

WITH sales AS (
  SELECT p.category,
         p.name AS product,
         SUM(oi.quantity) AS qty
  FROM order_items oi
  JOIN products p ON p.id = oi.product_id
  GROUP BY p.category, p.name
)
SELECT category, product, qty
FROM (
  SELECT s.*,
         ROW_NUMBER() OVER (
           PARTITION BY category ORDER BY qty DESC
         ) AS rn
  FROM sales s
) r
WHERE rn = 1;

โจทย์ที่ 7: ยอดรายได้สะสม

“แสดงยอดรายได้ที่ชำระแล้วสะสมรายวัน” การใช้ SUM แบบหน้าต่างร่วมกับกรอบที่เรียงลำดับจะสร้างยอดสะสมได้โดยไม่ต้องเชื่อมตารางกับตัวเอง

กล่าวถึงการกำหนดกรอบด้วย ROWS เพื่อให้ได้ยอดสะสมทีละแถวอย่างแท้จริง เพราะกรอบ RANGE เริ่มต้นอาจทำงานโดยไม่คาดคิดเมื่อวันที่มีค่าซ้ำกัน

SELECT order_date,
       SUM(daily) OVER (
         ORDER BY order_date
         ROWS BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW
       ) AS running_total
FROM (
  SELECT order_date, SUM(amount) AS daily
  FROM orders
  WHERE status = 'paid'
  GROUP BY order_date
) d
ORDER BY order_date;

โจทย์ที่ 8: วันที่มีการใช้งานต่อเนื่อง

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

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

WITH days AS (
  SELECT DISTINCT customer_id, order_date
  FROM orders WHERE status = 'paid'
),
grp AS (
  SELECT customer_id, order_date,
         order_date - (ROW_NUMBER() OVER (
           PARTITION BY customer_id ORDER BY order_date
         ) * INTERVAL '1 day') AS island
  FROM days
)
SELECT customer_id, COUNT(*) AS streak_len
FROM grp
GROUP BY customer_id, island
HAVING COUNT(*) >= 3;

ประสิทธิภาพและข้อผิดพลาดที่พบบ่อย

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

  • สร้างดัชนีให้คอลัมน์ที่ใช้เชื่อมและกรอง (เช่น orders(customer_id, status)) และหลีกเลี่ยงการใช้ฟังก์ชันกับคอลัมน์ที่มีดัชนีใน WHERE
  • เลือกใช้ EXISTS แทน IN สำหรับการเชื่อมเพื่อค้นหารายการที่ไม่ตรงกันขนาดใหญ่ เพราะ NOT IN ที่มีค่า NULL จะไม่คืนผลลัพธ์ใด ๆ อย่างเงียบ ๆ
  • การกรองคอลัมน์จากการเชื่อมแบบนอกใน WHERE จะเปลี่ยนเป็นการเชื่อมแบบด้านในโดยไม่รู้ตัว
  • เพิ่มตัวตัดสินกรณีเสมอเสมอ เพื่อให้ผลลัพธ์ N อันดับแรกกำหนดได้แน่นอน
  • ตรวจสอบแผน EXPLAIN ว่ามีการสแกนตามลำดับบนตารางขนาดใหญ่หรือไม่

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

คุณต้องการคำสั่งซื้อล่าสุดเพียงรายการเดียวของลูกค้าแต่ละราย และคำสั่งซื้อสองรายการอาจมีวันที่เดียวกัน

สรุปทบทวน: ชุดสัมภาษณ์จำลองเต็มรูปแบบ

คุณได้ทำโจทย์สัมภาษณ์ที่พบบ่อยที่สุดตั้งแต่ต้นจนจบ:

  • การรวมยอด + LIMIT สำหรับยอดใช้จ่าย N อันดับแรก
  • การเชื่อมเพื่อค้นหารายการที่ไม่ตรงกันด้วย NOT EXISTS (ปลอดภัยต่อค่า NULL)
  • DENSE_RANK สำหรับอันดับที่ N สูงสุด และ ROW_NUMBER สำหรับรายการล่าสุดของแต่ละคีย์และรายการอันดับหนึ่งของแต่ละกลุ่ม
  • LAG สำหรับการเปรียบเทียบเดือนต่อเดือน และ SUM OVER สำหรับยอดสะสม
  • เทคนิคหมายเลขแถวแบบ ช่วงขาดหายและช่วงต่อเนื่องสำหรับการหาช่วงต่อเนื่อง
  • ปิดท้ายทุกคำตอบด้วยการพูดถึงดัชนี EXPLAIN และข้อผิดพลาดที่พบบ่อย

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

บทเรียน “ชุดโจทย์สัมภาษณ์จำลองฉบับเต็ม” ฟรีหรือไม่

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

คุณจะเรียนรู้อะไรในบทเรียน “ชุดโจทย์สัมภาษณ์จำลองฉบับเต็ม”

โจทย์ครบกระบวนการแบบจับเวลา ซึ่งผสานการเชื่อมตาราง ฟังก์ชันหน้าต่าง และ CTE ภายใต้เงื่อนไขการสัมภาษณ์ คุณปฏิบัติ Coding Interview Prep ด้วยโค้ดที่ใช้งานได้จริงที่คุณเรียกใช้โดยตรงในเบราว์เซอร์ และติวเตอร์ AI ตลอด 24/7 ตอบคำถามของคุณขณะที่คุณไปผ่านบทเรียน

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

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

บทเรียน “ชุดโจทย์สัมภาษณ์จำลองฉบับเต็ม” ใช้เวลานานแค่ไหน

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

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

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

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

  1. การทำให้เป็นบรรทัดฐานจนถึง 3NF
  2. การสร้างแบบจำลอง ER และคาร์ดินาลิตีของความสัมพันธ์
  3. สคีมาแบบดาวและการออกแบบคลังข้อมูล
  4. ชุดโจทย์สัมภาษณ์จำลองฉบับเต็ม
← กลับไปที่ Coding Interview Prep