🇯🇵 日本語 | 🇺🇸 English | 🇪🇸 Español | 🇵🇹 Português | 🇹🇭 ไทย | 🇨🇳 中文

[SQL] ควบคุมจำนวนการแสดงผลด้วย LIMIT อย่างมืออาชีพ! ตั้งแต่พื้นฐานจนถึงการแบ่งหน้า

“สินค้าใหม่ 5 อันดับแรก”, “บทความยอดนิยม 10 อันดับแรก”, “หน้าที่ 1 ของผลการค้นหา”… บนเว็บไซต์หรือแอปพลิเคชัน เรามักจะต้องแสดงข้อมูลเพียงบางส่วนจากข้อมูลจำนวนมาก ฟังก์ชันที่ช่วยจำกัดจำนวนแถวใน SQL ก็คือ LIMIT นั่นเอง

บทความนี้เหมาะสำหรับนักพัฒนาเว็บไซต์ทุกคน โดยเราจะอธิบายตั้งแต่การใช้ LIMIT เบื้องต้น ไปจนถึงเทคนิคสำคัญในการพัฒนาเว็บคือ “การแบ่งหน้า (Pagination)” พร้อมตัวอย่างโค้ดมากมายและสภาพแวดล้อมสำหรับทดลองใช้งานที่คุณสามารถคัดลอกและนำไปใช้ได้ทันที ลองลงมือทำแล้วคุณจะเข้าใจการจัดการข้อมูลอย่างมีประสิทธิภาพมากยิ่งขึ้น!


วอร์มอัพกันก่อน! ใช้ข้อมูลตัวอย่างเหมือนเดิม

ก่อนเริ่มต้น เราจะใช้ตารางสินค้า (products) ของร้านค้าออนไลน์สมมติชื่อ “Web Creator's Mart” อีกครั้ง หากคุณเคยอ่าน บทความเรื่อง ORDER BY มาก่อน น่าจะคุ้นเคยกับตารางนี้อยู่แล้ว

โค้ด SQL ด้านล่างจะใช้ในการสร้างตารางและแทรกข้อมูล คุณสามารถทดลองบนเครื่องของคุณ หรือใช้ใน “สภาพแวดล้อมทดลอง” ที่เราจะพูดถึงภายหลัง ลองอ่านคร่าว ๆ สักรอบก่อนเริ่มก็จะดีครับ

-- สร้างตารางสินค้า

CREATE TABLE products (

  id INT,

  name VARCHAR(255),

  category VARCHAR(255),

  price INT,

  release_date DATE

);



-- แทรกข้อมูลตัวอย่าง (7 รายการ)

INSERT INTO products (id, name, category, price, release_date) VALUES

(1, 'หมอนนุ่มนิ่ม', 'ของแต่งบ้าน', 3200, '2023-04-15'),

(2, 'ที่ครอบหูลดเสียงรบกวน', 'แกดเจ็ต', 7800, '2023-11-01'),

(3, 'สมุดบันทึกไอเดีย', 'เครื่องเขียน', 1200, '2022-08-20'),

(4, 'คีย์บอร์ดเรืองแสง', 'แกดเจ็ต', 15000, '2023-06-30'),

(5, 'เก้าอี้นั่งสบายที่สุด', 'ของแต่งบ้าน', 32000, '2022-11-10'),

(6, 'ปากกาลื่นเขียนดี', 'เครื่องเขียน', 1200, '2023-09-01'),

(7, 'แก้วมัคสำหรับนักสร้างสรรค์', 'เครื่องครัว', 2500, '2023-04-15');

พร้อมหรือยัง? ถ้าพร้อมแล้ว มาเริ่มเข้าสู่โลกของ LIMIT กันเลย!


พื้นฐานของ LIMIT: การกำหนดจำนวนเรคคอร์ดที่ต้องการดึงข้อมูล

การใช้งาน LIMIT ที่ง่ายที่สุดคือการกำหนดจำนวนสูงสุดของเรคคอร์ด (แถว) ที่จะดึงมาแสดง วิธีเขียนก็ง่ายมาก เพียงแค่เพิ่ม LIMIT จำนวน ต่อท้ายคำสั่ง SELECT เท่านั้น

ตัวอย่างเช่น ดึงข้อมูล3 รายการแรกจากตาราง products

SELECT * FROM products LIMIT 3;

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

ดังนั้น LIMIT จะทรงพลังจริง ๆ ก็ต่อเมื่อใช้ร่วมกับ ORDER BY ที่เราได้เรียนรู้กันไปในบทความก่อนหน้า


คู่หูสุดแกร่ง! ORDER BY + LIMIT เพื่อดึง “N รายการแรก”

การดึงข้อมูลแบบ “TOP N รายการ” เช่น “3 สินค้าที่ราคาแพงที่สุด” หรือ “5 รายการที่เพิ่งวางขายล่าสุด” เป็นความต้องการที่พบได้บ่อยในเว็บไซต์ ซึ่งสามารถทำได้โดยใช้ ORDER BY จัดเรียงก่อน แล้วใช้ LIMIT จำกัดจำนวน

ลองดึง “3 สินค้าที่ราคาแพงที่สุด” โดยใช้ ORDER BY price DESC จัดเรียงจากแพงไปถูก แล้วตามด้วย LIMIT 3

-- ดึง 3 สินค้าที่ราคาแพงที่สุด
SELECT * FROM products ORDER BY price DESC LIMIT 3;

ได้ผลลัพธ์ไหมครับ? น่าจะได้ “เก้าอี้นั่งสบายที่สุด”, “คีย์บอร์ดมีไฟ” และ “ที่ครอบหูลดเสียงรบกวน” ตามลำดับนี้ วิธีนี้คือ สูตรทอง: เรียงลำดับด้วย ORDER BY แล้วค่อยตัดข้อมูลด้วย LIMIT ควรใช้ควบคู่กันเสมอ!

ถัดมา ลองดึง “2 รายการสินค้าที่วางขายล่าสุด” โดยใช้ release_date เป็นเกณฑ์

-- ดึง 2 สินค้าที่วางขายล่าสุด
SELECT * FROM products ORDER BY release_date DESC LIMIT 2;

เลื่อนจุดเริ่มต้นด้วย OFFSET

คู่หูอีกคนของ LIMIT คือ OFFSET ชื่อของมันก็บอกอยู่แล้วว่าใช้ “เลื่อน” จุดเริ่มต้น โดยสามารถ ข้ามข้อมูลก่อนหน้าจำนวนหนึ่งได้

ตัวอย่าง: “ขอ 2 สินค้าราคาแพงอันดับ 2 และ 3 โดยไม่รวมอันดับ 1” — นี่คือกรณีที่ OFFSET มีประโยชน์มาก

-- เรียงลำดับตามราคาจากมากไปน้อย, ข้าม 1 รายการแรก และดึง 2 รายการถัดไป
SELECT * FROM products ORDER BY price DESC LIMIT 2 OFFSET 1;

คำสั่งนี้มีความหมายดังนี้:

  1. ORDER BY price DESC: จัดเรียงสินค้าตามราคาจากแพงไปถูก
  2. OFFSET 1: ข้าม 1 รายการแรก
  3. LIMIT 2: ดึง 2 รายการถัดจากที่ข้ามไป

การใช้ LIMIT + OFFSET แบบนี้ คือหัวใจของการทำ “การแบ่งหน้า (Pagination)” ซึ่งจะพูดถึงในหัวข้อถัดไป


ขั้นสูง: ใช้ LIMIT และ OFFSET เพื่อสร้างการแบ่งหน้า (Pagination)

Pagination (การแบ่งหน้า) คือการแสดงข้อมูลจำนวนมากโดยแบ่งออกเป็นหลายหน้า เช่น รายการสินค้า หรือโพสต์บล็อก ซึ่งเราคุ้นเคยกับปุ่ม “1, 2, 3, … ถัดไป” อยู่บ่อยครั้ง

ฟีเจอร์นี้สามารถสร้างได้ด้วย LIMIT และ OFFSET สมมุติว่าเราแสดงสินค้า 3 รายการต่อหน้า

SQL ที่ใช้จะเป็นดังนี้ โดยเรียงลำดับด้วย id เพื่อให้แน่นอน

【SQL สำหรับหน้า 1】

-- หน้า 1: ไม่ข้าม และดึง 3 รายการ
SELECT * FROM products ORDER BY id LIMIT 3 OFFSET 0;

【SQL สำหรับหน้า 2】

-- หน้า 2: ข้าม 3 รายการ และดึง 3 รายการถัดไป
SELECT * FROM products ORDER BY id LIMIT 3 OFFSET 3;

【SQL สำหรับหน้า 3】

-- หน้า 3: ข้าม 6 รายการ และดึง 3 รายการถัดไป
SELECT * FROM products ORDER BY id LIMIT 3 OFFSET 6;

เห็นความเชื่อมโยงไหมครับ? ค่า LIMIT (แสดงต่อหน้า) คงที่ที่ 3 ส่วนค่า OFFSET จะเพิ่มเป็น 0, 3, 6, ... ซึ่งสามารถคำนวณได้จากสูตร:

OFFSET = (หมายเลขหน้าปัจจุบัน - 1) × จำนวนรายการต่อหน้า

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


【มาลองกันเถอะ!】ทดลองรัน SQL บนเบราว์เซอร์

ขอบคุณที่รอคอย! เราได้เตรียมสภาพแวดล้อมอินเทอร์แอคทีฟที่คุณสามารถรัน SQL ได้โดยตรงจากเบราว์เซอร์ของคุณเอง คุณสามารถทดลองคำสั่ง LIMIT ที่เรียนรู้จากบทความนี้ได้ทันที

คัดลอกโค้ดด้านล่างทั้งหมด บันทึกเป็นไฟล์ชื่อ index.html แล้วเปิดในเบราว์เซอร์ จากนั้นลองวาง SQL ตัวอย่างลงในกล่องข้อความแล้วกดปุ่ม "รัน SQL"

<!DOCTYPE html>
<html lang="th">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>สภาพแวดล้อมฝึก SQL</title>
  <style>
    body { font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif; line-height: 1.6; color: #333; max-width: 800px; margin: 2rem auto; padding: 0 1rem; }
    h1, h2 { color: #444; border-bottom: 2px solid #eee; padding-bottom: 0.3em;}
    textarea { width: 100%; height: 150px; font-family: monospace; font-size: 16px; padding: 10px; border: 1px solid #ccc; border-radius: 4px; box-sizing: border-box; margin-bottom: 1rem; }
    button { background-color: #007bff; color: white; padding: 10px 20px; border: none; border-radius: 4px; cursor: pointer; font-size: 16px; }
    button:hover { background-color: #0056b3; }
    #result-container { margin-top: 1.5rem; min-height: 100px;}
    table { width: 100%; border-collapse: collapse; margin-top: 1rem; }
    th, td { border: 1px solid #ddd; padding: 10px; text-align: left; }
    th { background-color: #f8f8f8; }
    #error-message { color: red; font-weight: bold; margin-top: 1rem; }
  </style>
</head>
<body>

  <h1>เรียนรู้ SQL ด้วยตัวคุณเอง! สนามฝึก LIMIT</h1>
  <p>ป้อนคำสั่ง SQL ของคุณในกล่องด้านล่าง แล้วกดปุ่ม "รัน SQL" ลองใช้ตัวอย่าง SQL ต่าง ๆ ที่อธิบายไว้ในบทความนี้ได้เลย!</p>

  <textarea id="sql-input">-- วาง SQL ของคุณตรงนี้เพื่อรัน
-- ตัวอย่าง: สินค้าราคาสูงสุด 3 อันดับแรก
SELECT * FROM products ORDER BY price DESC LIMIT 3;</textarea>
  <button onclick="executeQuery()">รัน SQL</button>

  <h2>ผลลัพธ์</h2>
  <div id="result-container"></div>
  <div id="error-message"></div>

  <script src="https://cdnjs.cloudflare.com/ajax/libs/sql.js/1.10.3/sql-wasm.js"></script>
  <script>
    let db;

    async function initDb() {
      try {
        const SQL = await initSqlJs({
          locateFile: file => `https://cdnjs.cloudflare.com/ajax/libs/sql.js/1.10.3/${file}`
        });
        db = new SQL.Database();
        
        const setupSQL = `
          CREATE TABLE products (id INT, name VARCHAR(255), category VARCHAR(255), price INT, release_date DATE);
          INSERT INTO products (id, name, category, price, release_date) VALUES
          (1, 'หมอนนุ่มนิ่ม', 'ของตกแต่งบ้าน', 3200, '2023-04-15'),
          (2, 'ที่ปิดหูสำหรับโฟกัส', 'แกดเจ็ต', 7800, '2023-11-01'),
          (3, 'สมุดจดความคิด', 'เครื่องเขียน', 1200, '2022-08-20'),
          (4, 'คีย์บอร์ดเรืองแสง', 'แกดเจ็ต', 15000, '2023-06-30'),
          (5, 'เก้าอี้นั่งสบายสุด ๆ', 'ของตกแต่งบ้าน', 32000, '2022-11-10'),
          (6, 'ปากกาลื่นเขียนดี', 'เครื่องเขียน', 1200, '2023-09-01'),
          (7, 'แก้วมัคสำหรับครีเอเตอร์', 'เครื่องครัว', 2500, '2023-04-15');
        `;
        db.run(setupSQL);
        executeQuery();
      } catch (e) {
        document.getElementById('error-message').textContent = 'การเริ่มต้นฐานข้อมูลล้มเหลว: ' + e.message;
      }
    }

    function executeQuery() {
      const sqlInput = document.getElementById('sql-input').value;
      const resultContainer = document.getElementById('result-container');
      const errorMessage = document.getElementById('error-message');
      
      resultContainer.innerHTML = '';
      errorMessage.innerHTML = '';

      try {
        const results = db.exec(sqlInput);
        if (results.length > 0) {
          resultContainer.appendChild(createTable(results[0]));
        } else {
          resultContainer.innerHTML = '<p>คำสั่งสำเร็จแต่ไม่มีข้อมูลที่จะแสดง (เช่น CREATE TABLE, INSERT)</p>';
        }
      } catch (e) {
        errorMessage.textContent = 'ข้อผิดพลาด: ' + e.message;
      }
    }

    function createTable(result) {
      const table = document.createElement('table');
      const thead = document.createElement('thead');
      const tbody = document.createElement('tbody');
      const headerRow = document.createElement('tr');
      result.columns.forEach(colName => {
        const th = document.createElement('th');
        th.textContent = colName;
        headerRow.appendChild(th);
      });
      thead.appendChild(headerRow);
      result.values.forEach(rowData => {
        const tr = document.createElement('tr');
        rowData.forEach(cellData => {
          const td = document.createElement('td');
          td.textContent = cellData;
          tr.appendChild(td);
        });
        tbody.appendChild(tr);
      });
      table.appendChild(thead);
      table.appendChild(tbody);
      return table;
    }

    initDb();
  </script>
</body>
</html>

เสริม: สำเนียงของฐานข้อมูลแต่ละประเภท

โครงสร้างคำสั่ง LIMIT ... OFFSET ... ที่อธิบายไว้ในบทความนี้เป็นรูปแบบมาตรฐานที่รองรับโดยฐานข้อมูลหลายประเภท เช่น MySQL, PostgreSQL และ SQLite อย่างไรก็ตาม บางระบบฐานข้อมูลใช้โครงสร้างที่แตกต่างกัน (สำเนียง) ซึ่งเราขอแนะนำไว้เป็นข้อมูลอ้างอิงดังนี้

ในกรณีของ SQL Server

สำหรับ Microsoft SQL Server เดิมทีจะใช้คำสั่ง TOP แต่ในเวอร์ชันใหม่ๆ มีการแนะนำให้ใช้โครงสร้าง OFFSET ... FETCH ... แทน

-- การแบ่งหน้าบน SQL Server (ข้าม 3 รายการ และดึงอีก 3 รายการถัดไป)
SELECT * FROM products
ORDER BY id
OFFSET 3 ROWS
FETCH NEXT 3 ROWS ONLY;

ในกรณีของ Oracle

ฐานข้อมูล Oracle ก็ใช้โครงสร้าง OFFSET ... FETCH ... ที่คล้ายกับ SQL Server

-- การแบ่งหน้าบน Oracle (ข้าม 3 รายการ และดึงอีก 3 รายการถัดไป)
SELECT * FROM products
ORDER BY id
OFFSET 3 ROWS
FETCH NEXT 3 ROWS ONLY;

จากตัวอย่างข้างต้นจะเห็นได้ว่า รูปแบบคำสั่งอาจแตกต่างกันตามประเภทของฐานข้อมูล แต่แนวคิดหลัก (ระบุจำนวนรายการที่ข้าม และจำนวนที่ต้องการดึง) นั้นเหมือนกัน


สรุป: ใครควบคุม LIMIT ได้ ก็สามารถควบคุมการแสดงผลข้อมูลได้!

บทความนี้ได้นำเสนอคำสั่ง LIMIT ของ SQL และคู่หูของมัน OFFSET ตั้งแต่พื้นฐานจนถึงระดับแอดวานซ์ มาทบทวนจุดสำคัญกันอีกครั้ง:

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