MSSQL 2000 → MySQL 5.x,系統重構導致資料庫結構差異大,不適合直接 ODBC 連結匯入,採用 PHP 腳本「讀 MSSQL → 轉換 → 寫 MySQL」彈性遷移。
| 方式 | 優點 | 缺點 | 適用場景 |
|---|---|---|---|
mssql_* 函數 | 語法類似 mysql_*,簡單 | PHP 5.3+ 已移除、僅支援舊版 FreeTDS | 舊專案維護 |
ODBC (odbc_*) | 跨資料庫抽象 | 無法以欄位名索引陣列、程式碼冗長 | 多資料庫支援 |
| PDO (PHP 5.1+) | 參數綁定防注入、統一介面、支援預處理、可移植 | 需 PHP 5.1+、啟用 pdo_mssql/pdo_dblib | 推薦:新專案首選 |
try {
$mssql = new PDO("dblib:host=localhost;dbname=src_db", "user", "pass");
$mysql = new PDO("mysql:host=localhost;dbname=dst_db", "user", "pass");
$mysql->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
} catch (PDOException $e) { die("Connect failed: " . $e->getMessage()); }
// 讀取 MSSQL
$stmt = $mssql->query("SELECT id, title, content, created FROM news");
while ($row = $stmt->fetch(PDO::FETCH_ASSOC)) {
// 轉換邏輯
$title = $row['title'];
$content = $row['content'];
$created = convertMssqlDateTime($row['created']); // 自訂函數
// 寫入 MySQL(參數綁定)
$ins = $mysql->prepare("INSERT INTO news(title, content, created) VALUES(?, ?, ?)");
$ins->execute([$title, $content, $created]);
}
修改 php.ini:
mssql.textlimit = -1
mssql.textsize = -1
或執行 SQL:SET TEXTSIZE 2147483647;(PDO 執行即可)。
MSSQL DATETIME 讀出為字串(如 Jan 1 2006 12:01PM),需解析為 Unix Timestamp:
function convertMssqlDateTime($str) {
if (!$str) return 0;
// 移除中文月份(若 php.ini 設定 mssql.datetimeconvert = Off 可避免)
$str = str_replace(
['一月','二月','三月','四月','五月','六月','七月','八月','九月','十月','十一月','十二月'],
['01','02','03','04','05','06','07','08','09','10','11','12'],
$str
);
return strtotime($str); // 或 DateTime::createFromFormat
}
最佳做法:在 php.ini 設定 mssql.datetimeconvert = Off,MSSQL 直接回傳 YYYY-MM-DD HH:MM:SS 格式,免解析。
| MSSQL | MySQL 建議 | 備註 |
|---|---|---|
| int / bigint | INT / BIGINT | |
| decimal(p,s) | DECIMAL(p,s) | |
| varchar(n) / nvarchar(n) | VARCHAR(n) / VARCHAR(n*3) utf8mb4 | nvarchar 需預留 3 倍長度 |
| text / ntext | TEXT / MEDIUMTEXT / LONGTEXT | 配合 textsize |
| datetime / smalldatetime | DATETIME / TIMESTAMP | Timestamp 範圍 1970-2038 |
| bit | TINYINT(1) | |
| uniqueidentifier | CHAR(36) / BINARY(16) | 存 UUID 字串或二進位 |
php migrate.php(無 HTTP 超時限制)。$mysql->commit(),避免長交易鎖表。SET FOREIGN_KEY_CHECKS=0; ALTER TABLE t DISABLE KEYS; → 匯入 → ENABLE KEYS; FOREIGN_KEY_CHECKS=1;SELECT COUNT(*) FROM news 雙邊一致。