資料插入是資料庫操作最基礎也最關鍵的環節。本文系統性介紹 INSERT 語法規則、MySQLi (物件導向/程序式) 與 PDO 完整實作、AUTO_INCREMENT/TIMESTAMP 自動欄位處理、SQL 注入防護、錯誤處理與最佳實務。
| 規則 | 說明 |
| 字串值 | 必須用單引號包裹 'value' |
| 數值 | 不需引號 123, 45.67 |
| NULL | 不需引號 NULL |
| 日期時間 | 字串格式 'YYYY-MM-DD HH:MM:SS' |
| 欄位清單 | 建議明確指定,避免結構變更導致錯誤 |
| 多筆插入 | VALUES (...), (...), (...) (單條 SQL) |
自動處理欄位:AUTO_INCREMENT 與 TIMESTAMP
定義表結構時:
CREATE TABLE MyGuests (
id INT(6) UNSIGNED AUTO_INCREMENT PRIMARY KEY,
firstname VARCHAR(30) NOT NULL,
lastname VARCHAR(30) NOT NULL,
email VARCHAR(50),
reg_date TIMESTAMP DEFAULT CURRENT_TIMESTAMP
);
id:插入時不指定,MySQL 自動產生唯一遞增值
reg_date:插入時不指定,自動填入當前時間戳
- 也可明確指定
DEFAULT 關鍵字:INSERT ... VALUES (DEFAULT, 'John', ...)
MySQLi 物件導向實作
<?php
$host = 'localhost'; $user = 'username'; $pass = 'password'; $db = 'myDB';
$mysqli = new mysqli($host, $user, $pass, $db);
if ($mysqli->connect_error) {
die("連線失敗: " . $mysqli->connect_error);
}
$sql = "INSERT INTO MyGuests (firstname, lastname, email) VALUES ('John', 'Doe', 'john@example.com')";
if ($mysqli->query($sql) === true) {
echo "新記錄插入成功";
echo "自動產生 ID: " . $mysqli->insert_id; // 獲取 AUTO_INCREMENT 值
} else {
echo "錯誤: " . $sql . "<br>" . $mysqli->error;
}
$mysqli->close();
MySQLi 程序式實作
$conn = mysqli_connect($host, $user, $pass, $db);
if (!$conn) {
die("連線失敗: " . mysqli_connect_error());
}
$sql = "INSERT INTO MyGuests (firstname, lastname, email) VALUES ('John', 'Doe', 'john@example.com')";
if (mysqli_query($conn, $sql)) {
echo "新記錄插入成功";
echo "自動產生 ID: " . mysqli_insert_id($conn);
} else {
echo "錯誤: " . $sql . "<br>" . mysqli_error($conn);
}
mysqli_close($conn);
PDO 實作 (推薦)
<?php
$host = 'localhost'; $user = 'username'; $pass = 'password'; $db = 'myDBPDO';
try {
$pdo = new PDO("mysql:host=$host;dbname=$db", $user, $pass);
$pdo->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
$pdo->setAttribute(PDO::ATTR_EMULATE_PREPARES, false); // 真實預處理
$sql = "INSERT INTO MyGuests (firstname, lastname, email) VALUES ('John', 'Doe', 'john@example.com')";
// exec() 用於無結果集的 INSERT/UPDATE/DELETE
$affected = $pdo->exec($sql);
echo "新記錄插入成功,影響行數: $affected";
echo "自動產生 ID: " . $pdo->lastInsertId();
} catch (PDOException $e) {
echo "錯誤: " . $sql . "<br>" . $e->getMessage();
}
$pdo = null;
安全插入:預處理語句 (必要實務)
絕不直接拼接變數到 SQL 字串。所有使用者輸入、外部資料必須使用參數綁定:
MySQLi 預處理插入
$stmt = $mysqli->prepare("INSERT INTO MyGuests (firstname, lastname, email) VALUES (?, ?, ?)");
$stmt->bind_param('sss', $firstname, $lastname, $email);
$firstname = $_POST['firstname'] ?? '';
$lastname = $_POST['lastname'] ?? '';
$email = $_POST['email'] ?? '';
$stmt->execute();
echo "ID: " . $stmt->insert_id;
$stmt->close();
PDO 預處理插入 (命名佔位符)
$stmt = $pdo->prepare("INSERT INTO MyGuests (firstname, lastname, email) VALUES (:fn, :ln, :em)");
$stmt->bindValue(':fn', $firstname);
$stmt->bindValue(':ln', $lastname);
$stmt->bindValue(':em', $email);
$stmt->execute();
echo "ID: " . $pdo->lastInsertId();
進階插入模式
1. INSERT IGNORE:忽略重複鍵錯誤
INSERT IGNORE INTO users (email, name) VALUES ('a@b.com', 'John');
// email 有 UNIQUE 索引時,重複不報錯、不插入、不影響 auto_increment
2. ON DUPLICATE KEY UPDATE:衝突時更新 (Upsert)
INSERT INTO users (email, name, login_count) VALUES ('a@b.com', 'John', 1)
ON DUPLICATE KEY UPDATE login_count = login_count + 1, name = VALUES(name);
3. REPLACE INTO:刪除舊行插入新行
REPLACE INTO users (id, email, name) VALUES (1, 'a@b.com', 'John');
// 若 id=1 存在,先 DELETE 再 INSERT (auto_increment 不變)
4. 批次插入多筆 (單條 SQL)
$sql = "INSERT INTO MyGuests (firstname, lastname, email) VALUES ";
$values = [];
$params = [];
foreach ($guests as $g) {
$values[] = "(?, ?, ?)";
$params[] = $g['firstname'];
$params[] = $g['lastname'];
$params[] = $g['email'];
}
$sql .= implode(', ', $values);
$stmt = $mysqli->prepare($sql);
// 動態綁定參數需 call_user_func_array 或迴圈 bindParam
// PDO 較簡單:
$stmt = $pdo->prepare($sql);
$stmt->execute($params);
錯誤處理與除錯
| 錯誤類型 | 檢查方式 | 常見原因 |
| 連線失敗 | $mysqli->connect_error / PDOException | 主機、帳號、密碼、資料庫名稱錯誤、防火牆 |
| SQL 語法錯誤 | $mysqli->error / $e->getMessage() | 引號不匹配、保留字未跳脫、欄位名拼錯 |
| 重複鍵衝突 | 錯誤碼 1062 (MySQLi) / 23000 (PDO) | PRIMARY KEY/UNIQUE 重複 |
| 外鍵約束失敗 | 錯誤碼 1452 | 參考資料不存在 |
| 資料過長 | 錯誤碼 1406 | VARCHAR 長度超限 |
| NOT NULL 違反 | 錯誤碼 1048 | 必填欄位未提供 |
最佳實務總結
- 永遠使用預處理語句:防注入、型別安全、計畫重用
- 明確指定欄位清單:
INSERT INTO t (a,b) VALUES (...) 而非 INSERT INTO t VALUES (...)
- 交易包裹多筆操作:確保原子性、大幅提升效能
- 檢查影響行數:
$stmt->affected_rows / $stmt->rowCount() 驗證預期結果
- 獲取自動 ID:
insert_id / lastInsertId() 立即取得
- 錯誤模式設為例外:PDO
ERRMODE_EXCEPTION,MySQLi 自行檢查或自定義例外包裝
- 關閉連線:腳本結束自動關閉,長執行程序手動
close()
總結
PHP MySQL 資料插入的核心在於安全參數化與正確錯誤處理。PDO 提供更現代、統一、例外導向的介面,是新專案首選。掌握 INSERT 變體 (IGNORE, ON DUPLICATE KEY UPDATE, REPLACE)、批次優化、交易控制,能應對從簡單表單提交到高併發資料寫入的各種場景。
- 上一篇文章: PHP MySQL 批次插入資料完全指南:多條 SQL、預處理語句與交易控制
- 下一篇文章: PHP MySQL 建立資料表完整指南:CREATE TABLE 語法、欄位屬性、索引與三大介面實作
Copyright ©
程式碼之家 All Rights Reserved