2016-08-19 59 views
5

似乎PDO與ISO 8601格式化的時間戳有問題。如何使用PDO綁定ISO8601 TSQL DATETIME參數?

我是從64位Ubuntu的連接使用16.04的Microsoft® ODBC Driver 13 (Preview) for SQL Server®

這裏是我的簡單的表運行PHP 7.0.8:

CREATE TABLE dtest (
    "stamp" DATETIME 
); 

作品:

$pdoDB = new PDO('odbc:Driver=ODBC Driver 13 for SQL Server; 
    Server='.DATABASE_SERVER.'; 
    Database='.DATABASE_NAME, 
    DATABASE_USERNAME, 
    DATABASE_PASSWORD 
); 
$pdoDB->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION); 

$sql = "INSERT INTO dtest (stamp) VALUES ('2011-03-15T10:23:01')"; 
$stmt = $pdoDB->prepare($sql); 
$params = []; 
$stmt->execute($params); 

不工作:

$sql = "INSERT INTO dtest (stamp) VALUES (?)"; 
$stmt = $pdoDB->prepare($sql); 
$params = ['2011-03-15T10:23:01']; 
$stmt->execute($params); 

Fatal error: Uncaught PDOException: SQLSTATE[22018]: Invalid character value for cast specification: 0 [Microsoft][ODBC Driver 13 for SQL Server]Invalid character value for cast specification (SQLExecute[0] at /build/php7.0-lPMnpS/php7.0-7.0.8/ext/pdo_odbc/odbc_stmt.c:260)

這工作如果我刪除了T所以'2011-03-15T10:23:01'成爲'2011-03-15 10:23:01'

$sql = "INSERT INTO dtest (stamp) VALUES (?)"; 
$stmt = $pdoDB->prepare($sql); 
$params = ['2011-03-15 10:23:01']; 
$stmt->execute($params); 

但我正在寫在夜間運行在約2萬條記錄的腳本,所以我倒是真的不忍心運行數百萬的開銷str_replace('T', ' ', $param)

我也試過用bindParam,但是它給出了同樣的錯誤

$sql = "INSERT INTO dtest (stamp) VALUES (:tdate)"; 
$stmt = $pdoDB->prepare($sql); 
$date = '2011-03-15T10:23:01'; 
$stmt->bindParam(':tdate',$date,PDO::PARAM_STR); 
$stmt->execute(); 

是否有無論如何綁定和執行這個參數?我有點疑惑的錯誤信息,因爲它似乎來自SQL Server,就好像PDO做得很好,但這沒有意義,因爲它能夠處理不帶參數化的類型轉換。


我也試過SQL轉換:

作品:

$sql = "INSERT INTO dtest (stamp) VALUES (CONVERT(DATETIME, '2011-03-15T10:23:02', 126))"; 
$stmt = $pdoDB->prepare($sql); 
$params = []; 
$stmt->execute($params); 

不起作用:

$sql = "INSERT INTO dtest (stamp) VALUES (CONVERT(DATETIME, ?, 126))"; 
$stmt = $pdoDB->prepare($sql); 
$params = ['2011-03-15T10:23:02']; 
$stmt->execute($params); 
+0

嗨,這有什麼好運? – MonkeyZeus

+0

@MonkeyZeus nope,但我整個週末都休息了,所以今天我會再試一次。 –

+0

祝你好運!讓我知道它是怎麼回事 – MonkeyZeus

回答

1

您將需要使用SQL Server的內置convert()功能並指定格式()你哪一個重新給它:

$sql = "INSERT INTO dtest (stamp) VALUES (CONVERT(DATETIME, '2011-03-15T10:23:01', 126))"; 

的文件在你的字符串末尾提到:mmm所以你可能需要在你的日期字符串末尾手動添加:000這個工作。

+0

感謝您的回答,但是在嘗試使用'$ sql =「插入dtest(stamp)VALUES(convert(?,126))時會得到相同的錯誤」;'還要注意,沒有準備的語句在沒有轉換的情況下工作得很好。 '$ sql =「INSERT INTO dtest(stamp)VALUES('2011-03-15T10:23:01')」;'這是導致問題的綁定過程。 –

+0

實際上,這會導致額外的'語法錯誤或訪問衝突:'@ P1'附近的語法錯誤。' –

+0

@JeffPuckettII哎呀!對不起,我應該更仔細地閱讀你的問題細節。雖然這很奇怪。你有沒有考慮過使用['bindParam()'](http://php.net/manual/en/pdostatement.bindparam.php)而不是'PARAM_STR'來看看情況會有所好轉? – MonkeyZeus

1

花了半天的時間試圖解決同一個問題,我最終放棄了odbc並使用dblib代替。我安裝了php7.0-sybase軟件包,調整了我的PDO連接的數據源名稱,併爲所有人解決了問題。 現在每個綁定都在工作。

+0

從技術上講,這不是具體問題的答案,但它是一個非常好的替代方案,我非常想要「接受」它。你是對的,我一直非常喜歡Sybase的驅動程序,以至於我在很久以前還沒有使用過ODBC。但是我知道將來會有更多的項目(例如DB2)需要ODBC,希望有人能夠回答這個問題。 –