應用從 MySQL 遷移至其他數據庫(PostgreSQL、SQL Server、Oracle、Access 等)時,原生 SQL 方言差異導致插入/更新失敗。ADOdb(PHP 跨數據庫抽象層)提供統一 API 吸收差異,本文總結核心遷移模式。
DBDate()MySQL 默認 YYYY-MM-DD,SQL Server MM/DD/YYYY,Oracle DD-MON-YY,Access #MM/DD/YYYY#。
$sql = "INSERT INTO events (event_date) VALUES (" . $db->DBDate($timestamp) . ")";
$db->Execute($sql);
DBDate() 根據目標數據庫自動輸出正確字面量格式。
qstr()MySQL 使用反斜杠轉義(don\'t),SQL Server/Access 使用雙單引號(don''t),PostgreSQL 標準單引號轉義(don't 或 E'don\'t')。
$note = "sugar why don't we call it off";
$sql = "INSERT INTO notes (content) VALUES (" . $db->qstr($note) . ")";
$db->Execute($sql);
qstr() 自動處理引號轉義、NULL 值(返回 NULL 而非空字符串)、二進制數據編碼。
$ID = 3;
$TheDate = mktime(0,0,0,8,31,2001); // 2001-08-31
$Note = "sugar why don't we call it off";
$sql = "INSERT INTO mytable (id, thedate, note) VALUES ("
. $ID . ", "
. $db->DBDate($TheDate) . ", "
. $db->qstr($Note) . ")";
$db->Execute($sql);
$affected = $connection->Affected_Rows(); // UPDATE/DELETE 影響行數
$insertId = $recordset->Insert_ID(); // 最後一條 INSERT 自增 ID
// 注意:並非所有驅動均支持,使用前請查閱對應驅動文檔
$recordset = $conn->Execute("SELECT adate FROM table");
$f0 = $recordset->FetchField(0);
// $f0->name = 'adate'
// $f0->type = 'date' (原生類型名,各庫不同)
// $f0->max_length = -1 (未知時)
MetaType()ADOdb 將各數據庫原生類型映射為統一類別:
| MetaType | 含義 | 典型原生類型示例 |
|---|---|---|
| C | 字符/定長字符 | CHAR, VARCHAR |
| X | 長文本/LOB | TEXT, LONGTEXT, CLOB, MEMO |
| B | 二進制大對象 | BLOB, BYTEA, IMAGE |
| D | 日期 | DATE |
| T | 時間戳/日期時間 | DATETIME, TIMESTAMP |
| N | 數值 | INT, DECIMAL, NUMBER |
| I | 整數 | INTEGER, SERIAL |
| R | 自增/序列 | AUTO_INCREMENT, IDENTITY, SEQUENCE |
| L | 邏輯/布爾 | BOOL, BIT, TINYINT(1) |
$metaType = $db->MetaType($f0->type, $f0->max_length);
// 統一邏輯判斷
if ($metaType == 'D') { /* 日期字段處理 */ }
$db->DBDate()$db->qstr()LIMIT 分頁語法差異(MySQL/PostgreSQL: LIMIT 10 OFFSET 20;SQL Server: OFFSET 20 ROWS FETCH NEXT 10 ROWS ONLY;Oracle: ROWNUM 子查詢)— ADOdb SelectLimit() 可抹平。Insert_ID() vs LAST_INSERT_ID() vs SCOPE_IDENTITY())