如何将 ISO8601 TSQL DATETIME 参数与 PDO 绑定?
Posted
技术标签:
【中文标题】如何将 ISO8601 TSQL DATETIME 参数与 PDO 绑定?【英文标题】:How to bind ISO8601 TSQL DATETIME parameter with PDO? 【发布时间】:2016-12-26 21:49:41 【问题描述】:看来 PDO 的ISO 8601 格式化时间戳有问题。
我使用Microsoft® ODBC Driver 13 (Preview) for SQL Server®从运行 php 7.0.8 的 64 位 Ubuntu 16.04 连接
这是我的简单表格:
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);
致命错误:未捕获的 PDOException:SQLSTATE[22018]:转换规范的字符值无效:0 [Microsoft][SQL Server 的 ODBC 驱动程序 13]转换规范的字符值无效(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);
但我正在编写一个每晚在大约 200 万条记录上运行的脚本,所以我真的宁愿不承担运行数百万条 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);
【问题讨论】:
你好,你好运吗? @MonkeyZeus 不,但我整个周末都休息了,所以今天我要再试一次。 祝你好运!告诉我进展如何 @JeffPuckettII 你能解决这个问题吗?这不仅发生在日期上,还发生在所有绑定参数上。 @Frondor 对于这个特定的问题,我正在导入安全(预清理)数据,所以我完全跳过了绑定。不是用户输入的解决方案,所以不,我还没有解决它。我只是尽量避免微软支持不佳的垃圾。 【参考方案1】:您需要使用 SQL Server 的内置 convert()
函数并指定您提供的格式 (126):
$sql = "INSERT INTO dtest (stamp) VALUES (CONVERT(DATETIME, '2011-03-15T10:23:01', 126))";
文档在字符串末尾提到 :mmm
,因此您可能需要在日期字符串末尾手动添加 :000
才能使其正常工作。
【讨论】:
感谢您的回答,但我在尝试$sql = "INSERT INTO dtest (stamp) VALUES (convert(?, 126))";
时遇到同样的错误另请注意,未经准备的语句无需转换即可正常工作。 $sql = "INSERT INTO dtest (stamp) VALUES ('2011-03-15T10:23:01')";
是绑定过程导致问题。
其实这会导致额外的Syntax error or access violation: 102 Incorrect syntax near '@P1'.
@JeffPuckettII 哎呀!很抱歉,我应该更仔细地阅读您的问题详细信息。不过这很奇怪。您是否考虑过将bindParam()
与PARAM_STR
一起使用,看看情况是否会好转?
不,这给出了同样的错误 - 我已经通过尝试更新了我的问题。
@JeffPuckettII 我完全没有想法,mssql 驱动程序可能只是有一个未解决的错误:(【参考方案2】:
花了半天时间试图解决同样的问题后,我最终放弃了 odbc 并改用了 dblib。我安装了 php7.0-sybase 包,修改了我的 PDO 连接的数据源名称并一劳永逸地解决了。 现在每个绑定都在工作。
【讨论】:
从技术上讲,这不是特定问题的答案,但它是一个非常好的解决方法,我非常想“接受”它。你是对的,我非常喜欢 Sybase 驱动程序,以至于我已经很久没有使用过 ODBC。但我知道我将来会有更多需要 ODBC 的项目(例如 DB2),希望有人能特别回答这个问题。以上是关于如何将 ISO8601 TSQL DATETIME 参数与 PDO 绑定?的主要内容,如果未能解决你的问题,请参考以下文章
如何使用 ISO 8601 格式的 DateTime 字段将 JSON 文本反序列化为 BsonDocument?
如何从 ISO 8601 格式创建 .NET DateTime