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

[คัดลอกและวางได้เลย] คู่มือการใช้ฟังก์ชัน COUNT ของ SQL อย่างละเอียด ตั้งแต่พื้นฐานจนถึงขั้นสูง

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

COUNT() เป็นฟังก์ชันการรวม (aggregate function) ที่ใช้ในการนับจำนวนแถว (records) ในตาราง ฟังดูเรียบง่าย แต่ขึ้นอยู่กับวิธีใช้ เราสามารถดึงข้อมูลได้หลากหลายรูปแบบ ฟังก์ชันนี้มีความลึกและทรงพลังมาก ในบทความนี้เราจะอธิบายวิธีใช้งานตั้งแต่พื้นฐานไปจนถึงการประยุกต์ใช้จริง พร้อมโค้ดตัวอย่างที่สามารถคัดลอกและวางได้ทันที เหมาะสำหรับผู้เริ่มต้นที่ต้องการเป็นนักพัฒนาเว็บ

เป้าหมายของบทความนี้คือช่วยให้คุณได้สัมผัสความรู้สึกว่า “SQL มันทำงานได้จริงเมื่อเราเขียน!” ทิ้งทฤษฎีที่ซับซ้อนไว้ก่อน! เริ่มต้นจากการคัดลอกโค้ด รัน แล้วดูผลลัพธ์ เพื่อค้นหาความสนุกของ SQL ด้วยตัวคุณเอง


เริ่มต้นวอร์มอัป! สร้างข้อมูลตัวอย่าง

การจะทดลอง SQL ได้นั้น จำเป็นต้องมีตารางที่มีข้อมูล ในบทความนี้เราจะสร้างตาราง users ซึ่งเป็นรายการผู้ใช้ตัวอย่าง โค้ด SQL ด้านล่างนี้ใช้สำหรับสร้างตารางและใส่ข้อมูลทดสอบ

โค้ดทั้งหมดในบทความนี้จะอ้างอิงกับตาราง users นี้

-- ลบตารางหากมีอยู่แล้ว (เพื่อให้ทดลองซ้ำได้)
DROP TABLE IF EXISTS users;

-- สร้างตาราง users
CREATE TABLE users (
  id INTEGER PRIMARY KEY,
  name TEXT NOT NULL,
  prefecture TEXT NOT NULL,
  email TEXT
);

-- เพิ่มข้อมูล
INSERT INTO users (id, name, prefecture, email) VALUES
(1, 'Taro Yamada', 'Tokyo', 'yamada@example.com'),
(2, 'Hanako Suzuki', 'Osaka', 'suzuki@example.com'),
(3, 'Jiro Sato', 'Tokyo', NULL),
(4, 'Sakura Ito', 'Fukuoka', 'ito@example.com'),
(5, 'Saburo Watanabe', 'Hokkaido', 'watanabe@example.com'),
(6, 'Shiro Takahashi', 'Tokyo', 'takahashi@example.com'),
(7, 'Misaki Tanaka', 'Osaka', NULL);

ตารางนี้ประกอบด้วยคอลัมน์ ID, ชื่อ, จังหวัด และอีเมล จุดสำคัญคืออีเมลของคุณ Sato (ID 3) และคุณ Tanaka (ID 7) เป็น NULL (ไม่มีข้อมูล) ซึ่งจุดนี้จะส่งผลกับการทำงานของ COUNT() ในภายหลัง


[พื้นฐาน 1] นับจำนวนเรคคอร์ดทั้งหมดด้วย `COUNT(*)`

มาเริ่มจากการใช้งานที่ง่ายที่สุด คือ COUNT(*) เครื่องหมายดอกจัน (*) หมายถึง “ทุกคอลัมน์” และ COUNT(*) จะคืนค่าจำนวนแถวทั้งหมดในตาราง ใช้เมื่อต้องการรู้ว่า “มีข้อมูลทั้งหมดกี่รายการ?”

ลองนับจำนวนผู้ใช้ทั้งหมดจากตาราง users

SELECT COUNT(*) FROM users;

ผลลัพธ์:

7

เราใส่ข้อมูลไว้ 7 รายการ ผลลัพธ์จึงเป็น “7” ซึ่งถูกต้อง นี่คือพื้นฐานของการใช้ COUNT()


[พื้นฐาน 2] ระบุคอลัมน์เพื่อให้นับเฉพาะ `COUNT(column_name)`

ถัดมาเราจะดูการใช้ COUNT(column_name) ซึ่งเป็นการนับจำนวนแถวที่มี “ข้อมูลอยู่” ในคอลัมน์ที่ระบุ

จุดสำคัญคือ COUNT(column_name) จะไม่นับค่าที่เป็น NULL กล่าวคือ แถวที่ไม่มีข้อมูลในคอลัมน์นั้นจะไม่ถูกนับ

ลองนับจำนวนผู้ใช้ที่มีอีเมลในตาราง users

SELECT COUNT(email) FROM users;

ผลลัพธ์:

5

ผลลัพธ์คือ “5” ซึ่งน้อยกว่าค่า “7” ของ COUNT(*) เพราะ Sato และ Tanaka มีค่า NULL ในคอลัมน์ email และจึงไม่ถูกนับ

จำให้แม่นว่า COUNT(*) คือจำนวนแถวทั้งหมด ส่วน COUNT(column_name) คือนับเฉพาะแถวที่มีข้อมูลในคอลัมน์นั้น


[ขั้นสูง 1] ตั้งชื่อผลลัพธ์ด้วย `AS`

โดยปกติผลลัพธ์จาก COUNT() จะแสดงชื่อคอลัมน์เป็น COUNT(*) หรือ COUNT(email) ซึ่งอาจอ่านยาก

ในกรณีนี้สามารถใช้ AS เพื่อกำหนดชื่อคอลัมน์ใหม่ให้อ่านง่ายขึ้น

SELECT COUNT(*) AS total_users FROM users;

ผลลัพธ์:

total_users
-----------
7

ด้วยการใช้ AS total_users คอลัมน์ผลลัพธ์เปลี่ยนชื่อเป็น total_users ช่วยให้เข้าใจง่ายขึ้น และยังสามารถเข้าถึงผลลัพธ์ผ่านโค้ดได้สะดวก เช่น result['total_users']


[ขั้นสูง 2] นับเฉพาะค่าที่ไม่ซ้ำด้วย `COUNT(DISTINCT column_name)`

ต่อไปคือ COUNT(DISTINCT) ซึ่งใช้บ่อยมากในการวิเคราะห์เว็บไซต์ คำสั่ง DISTINCT มีความหมายว่า “ตัดค่าที่ซ้ำกันออก” ทำให้สามารถนับจำนวนค่าที่ไม่ซ้ำได้

เช่น “มีผู้ใช้งานมาจากจังหวัดทั้งหมดกี่จังหวัด?”

ในตาราง users มีผู้ใช้จาก Tokyo 3 คน, Osaka 2 คน มาลองนับจำนวนจังหวัดที่ไม่ซ้ำกัน

SELECT COUNT(DISTINCT prefecture) AS unique_prefectures FROM users;

ผลลัพธ์:

unique_prefectures
------------------
4

ผลลัพธ์คือ “4” เพราะมี Tokyo, Osaka, Fukuoka และ Hokkaido รวม 4 จังหวัดที่ไม่ซ้ำกัน

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


[ขั้นสูง 3] นับแยกตามกลุ่มด้วย `GROUP BY`

COUNT() จะมีประสิทธิภาพสูงสุดเมื่อใช้งานร่วมกับคำสั่ง GROUP BY ซึ่งใช้จัดกลุ่มแถวที่มีค่าคอลัมน์เดียวกัน จากนั้นใช้ COUNT() กับแต่ละกลุ่มได้

เช่น “อยากรู้จำนวนผู้ใช้ในแต่ละจังหวัด” — นี่แหละเวลาที่ GROUP BY เหมาะสมที่สุด

SELECT
  prefecture,
  COUNT(*) AS user_count
FROM
  users
GROUP BY
  prefecture;

ผลลัพธ์:

prefecture | user_count
-----------|------------
Osaka      | 2
Hokkaido   | 1
Tokyo      | 3
Fukuoka    | 1

ยอดเยี่ยม! เราได้รายการจำนวนผู้ใช้แยกตามจังหวัด โดยใช้ prefecture เพื่อจัดกลุ่ม และ COUNT(*) เพื่อนับจำนวนแถวในแต่ละกลุ่ม

เทคนิคนี้มีความสำคัญมากในการวิเคราะห์ข้อมูล เช่น ตรวจสอบว่าผู้ใช้ส่วนใหญ่มาจากภูมิภาคใด


[ระดับโปร] กำหนดเงื่อนไขกับผลรวมด้วย `HAVING`

บางครั้งคุณอาจต้องการกรองผลลัพธ์หลังจากใช้ GROUP BY เช่น “แสดงเฉพาะจังหวัดที่มีผู้ใช้อย่างน้อย 2 คน”

ข้อน่าสังเกตคือ คำสั่ง WHERE ใช้กรองข้อมูลก่อนการจัดกลุ่ม ดังนั้นจะใช้ไม่ได้กับค่าผลรวม เช่น user_count

หากต้องการกรองหลังจากจัดกลุ่ม ต้องใช้คำสั่ง HAVING

SELECT
  prefecture,
  COUNT(*) AS user_count
FROM
  users
GROUP BY
  prefecture
HAVING
  user_count >= 2;

ผลลัพธ์:

prefecture | user_count
-----------|------------
Osaka      | 2
Tokyo      | 3

เมื่อเพิ่มเงื่อนไข HAVING user_count >= 2 เราจะได้เฉพาะจังหวัดที่มีผู้ใช้อย่างน้อย 2 คน คือ Osaka และ Tokyo

จำไว้ว่า WHERE ใช้กับแถวก่อนการจัดกลุ่ม ส่วน HAVING ใช้กับผลลัพธ์หลังการจัดกลุ่มด้วย GROUP BY


[มุมโต้ตอบ] ลองรัน SQL ในเบราว์เซอร์ของคุณ!

ขอบคุณที่รอ! เราได้จัดเตรียมสภาพแวดล้อมที่คุณสามารถรัน SQL ที่เรียนรู้มาด้วยมือของคุณเองแล้ว

คัดลอกโค้ด HTML ทั้งหมดด้านล่าง บันทึกเป็นไฟล์ชื่อเช่น sql_test.html และเปิดในเบราว์เซอร์ของคุณ ตาราง users ที่นำเสนอในบทความนี้ถูกเตรียมไว้แล้ว ลองใช้คำสั่ง SQL หลายๆ แบบและดูผลลัพธ์ที่เปลี่ยนแปลง!

<!DOCTYPE html>
<html lang="ja">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>สภาพแวดล้อมรัน SQL สำหรับ COUNT()</title>
  <style>
    body { font-family: sans-serif; line-height: 1.6; color: #333; max-width: 800px; margin: 2rem auto; padding: 0 1rem; }
    h1 { color: #444; }
    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; border: none; padding: 10px 20px; font-size: 16px; border-radius: 4px; cursor: pointer; }
    button:hover { background-color: #0056b3; }
    button:disabled { background-color: #ccc; cursor: not-allowed; }
    #result-container { margin-top: 2rem; border: 1px solid #ddd; padding: 1rem; border-radius: 4px; background: #f9f9f9; min-height: 50px; }
    #error-message { color: #d9534f; font-weight: bold; }
    table { border-collapse: collapse; width: 100%; margin-top: 1rem; }
    th, td { border: 1px solid #ddd; padding: 8px; text-align: left; }
    th { background-color: #f2f2f2; }
  </style>
  <script src="https://cdnjs.cloudflare.com/ajax/libs/sql.js/1.10.3/sql-wasm.js"></script>
</head>
<body>

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

  <textarea id="sql-input">SELECT prefecture, COUNT(*) AS user_count
FROM users
GROUP BY prefecture
HAVING user_count >= 2;</textarea>
  
  <button id="execute-btn">รัน</button>
  
  <div id="result-container">
    <p id="error-message"></p>
    <div id="result-output"></div>
  </div>

  <script>
    const sqlInput = document.getElementById('sql-input');
    const executeBtn = document.getElementById('execute-btn');
    const errorMsg = document.getElementById('error-message');
    const resultOutput = document.getElementById('result-output');

    let db;

    async function initDb() {
      executeBtn.disabled = true;
      executeBtn.textContent = 'กำลังเตรียม...';
      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 = `
          DROP TABLE IF EXISTS users;
          CREATE TABLE users (
            id INTEGER PRIMARY KEY,
            name TEXT NOT NULL,
            prefecture TEXT NOT NULL,
            email TEXT
          );
          INSERT INTO users (id, name, prefecture, email) VALUES
          (1, 'Taro Yamada', 'Tokyo', 'yamada@example.com'),
          (2, 'Hanako Suzuki', 'Osaka', 'suzuki@example.com'),
          (3, 'Jiro Sato', 'Tokyo', NULL),
          (4, 'Sakura Ito', 'Fukuoka', 'ito@example.com'),
          (5, 'Saburo Watanabe', 'Hokkaido', 'watanabe@example.com'),
          (6, 'Shiro Takahashi', 'Tokyo', 'takahashi@example.com'),
          (7, 'Misaki Tanaka', 'Osaka', NULL);
        `;
        db.run(setupSql);
        
        executeBtn.disabled = false;
        executeBtn.textContent = 'รัน';
        resultOutput.innerHTML = '<p>พร้อมแล้ว! ป้อน SQL ของคุณและคลิก รัน ได้เลย</p>';

      } catch (err) {
        errorMsg.textContent = 'ไม่สามารถเตรียมฐานข้อมูลได้: ' + err.message;
        console.error(err);
      }
    }

    function executeSql() {
      if (!db) return;
      
      const sql = sqlInput.value;
      errorMsg.textContent = '';
      resultOutput.innerHTML = '';

      try {
        const results = db.exec(sql);
        if (results.length === 0) {
          resultOutput.innerHTML = '<p>คิวรีสำเร็จ แต่ไม่มีชุดผลลัพธ์ส่งกลับ (เช่น INSERT, UPDATE ฯลฯ)</p>';
          return;
        }
        
        results.forEach(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(row => {
            const bodyRow = document.createElement('tr');
            row.forEach(cellValue => {
              const td = document.createElement('td');
              td.textContent = cellValue === null ? 'NULL' : cellValue;
              bodyRow.appendChild(td);
            });
            tbody.appendChild(bodyRow);
          });
          
          table.appendChild(thead);
          table.appendChild(tbody);
          resultOutput.appendChild(table);
        });

      } catch (err) {
        errorMsg.textContent = 'ข้อผิดพลาดของ SQL: ' + err.message;
        console.error(err);
      }
    }

    executeBtn.addEventListener('click', executeSql);
    
    initDb();
  </script>
</body>
</html>

【ลองใช้งานกันเถอะ!】


จุดที่ควรระวังและเกร็ดความรู้

COUNT(*) vs COUNT(1) vs COUNT(column_name)

บางครั้งจะเห็นรูปแบบ COUNT(1) ซึ่งหมายความว่ามีการกำหนดค่า “1” ให้แต่ละแถว แล้วนับจำนวนของค่านั้น ในฐานข้อมูลส่วนใหญ่ COUNT(*) และ COUNT(1) จะให้ผลลัพธ์และประสิทธิภาพเหมือนกัน เพราะทั้งสองนับทุกแถว ส่วน COUNT(column_name) จะไม่นับค่า NULL ตามที่อธิบายไว้ก่อนหน้านี้ จึงใช้ในวัตถุประสงค์ที่ต่างกัน หากไม่แน่ใจ ให้ใช้ COUNT(*) หากต้องการนับทุกแถว หรือ COUNT(column_name) หากต้องการนับเฉพาะค่าที่ไม่เป็น NULL

ประสิทธิภาพ

หากใช้ COUNT(*) กับตารางขนาดใหญ่ที่มีหลายล้านแถว อาจใช้เวลานาน โดยเฉพาะเมื่อไม่มีเงื่อนไขใดๆ เพราะจะต้องสแกนข้อมูลทั้งหมด หากจำเป็นต้องนับจำนวนรวมบ่อยๆ อาจพิจารณาวิธีอื่น เช่น การสร้างตารางสรุปข้อมูล แต่ในเบื้องต้นเพียงแค่รู้วิธีใช้งานพื้นฐานก็เพียงพอ


ฟังก์ชันที่เกี่ยวข้อง: ฟังก์ชันการรวมอื่นๆ

เมื่อเข้าใจ COUNT() แล้ว ฟังก์ชันการรวมอื่นๆ ก็สามารถเรียนรู้ได้ง่ายเช่นกัน โดยจะทรงพลังมากเมื่อใช้ร่วมกับ GROUP BY

ตัวอย่างเช่น หากต้องการทราบรหัสผู้ใช้ที่มากที่สุด ให้ใช้โค้ดนี้:

SELECT MAX(id) AS latest_user_id FROM users;

สรุป

บทความนี้ได้แนะนำการใช้ฟังก์ชัน COUNT() ตั้งแต่พื้นฐานจนถึงการประยุกต์ใช้งานในเชิงลึก

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