2016-08-19 58 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,希望有人能够回答这个问题。 –