[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;
คำสั่งนี้มีความหมายดังนี้:
ORDER BY price DESC: จัดเรียงสินค้าตามราคาจากแพงไปถูกOFFSET 1: ข้าม 1 รายการแรกLIMIT 2: ดึง 2 รายการถัดจากที่ข้ามไป
การใช้ LIMIT + OFFSET แบบนี้ คือหัวใจของการทำ “การแบ่งหน้า (Pagination)” ซึ่งจะพูดถึงในหัวข้อถัดไป
ขั้นสูง: ใช้ LIMIT และ OFFSET เพื่อสร้างการแบ่งหน้า (Pagination)
Pagination (การแบ่งหน้า) คือการแสดงข้อมูลจำนวนมากโดยแบ่งออกเป็นหลายหน้า เช่น รายการสินค้า หรือโพสต์บล็อก ซึ่งเราคุ้นเคยกับปุ่ม “1, 2, 3, … ถัดไป” อยู่บ่อยครั้ง
ฟีเจอร์นี้สามารถสร้างได้ด้วย LIMIT และ OFFSET สมมุติว่าเราแสดงสินค้า 3 รายการต่อหน้า
- หน้า 1: ดึง 3 รายการแรก (ไม่ต้องข้ามข้อมูล)
- หน้า 2: ข้าม 3 รายการแรก แล้วดึง 3 ถัดไป
- หน้า 3: ข้าม 6 รายการแรก แล้วดึง 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 ตั้งแต่พื้นฐานจนถึงระดับแอดวานซ์ มาทบทวนจุดสำคัญกันอีกครั้ง:
LIMITใช้สำหรับจำกัดจำนวนรายการที่ดึงออกมา- มักใช้ร่วมกับ
ORDER BYเพื่อดึง "รายการ N อันดับแรก" OFFSETใช้เพื่อเลื่อนตำแหน่งเริ่มต้นของการดึงข้อมูล (เช่น ข้าม N รายการแรก)- เมื่อใช้
LIMITร่วมกับOFFSETจะสามารถสร้าง ระบบแบ่งหน้า (Pagination) ซึ่งจำเป็นสำหรับการพัฒนาเว็บไซต์
การดึงข้อมูลอย่างชาญฉลาดเฉพาะเท่าที่จำเป็น จะช่วยเพิ่มประสิทธิภาพของฐานข้อมูล และทำให้ผู้ใช้ได้รับประสบการณ์ที่ดี ลองทดสอบในเดโมที่เตรียมไว้ แล้วคุณจะเข้าใจการทำงานของมันอย่างถ่องแท้!