How to bind ISO8601 TSQL DATETIME parameter with PDO?

一笑奈何 提交于 2019-11-28 08:08:38

问题


It seems that PDO has a problem with ISO 8601 formatted timestamps.

I'm connecting from 64-bit Ubuntu 16.04 running PHP 7.0.8 using the Microsoft® ODBC Driver 13 (Preview) for SQL Server®

Here's my simple table:

CREATE TABLE dtest (
    "stamp" DATETIME
);

Works:

$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);

Does not work:

$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)

This works if I delete the T so '2011-03-15T10:23:01' becomes '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);

But I'm writing a script that runs nightly on about 2 million records, so I'd really rather not bear the overhead of running millions of str_replace('T', ' ', $param)

I've also tried using bindParam, but it gives the same error:

$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();

Is there anyway to bind and execute this parameter as is? I'm a little dubious of the error message because it appears to be coming from SQL Server as if PDO did its job fine, but that doesn't make sense since it's able to handle the type conversion without parameterization.


I've also tried SQL conversion:

Works:

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

Does not Work:

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

回答1:


You will need to use SQL Server's built-in convert() function and specify the format (126) which you are giving it:

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

The documentation mentions :mmm at the end of your string so you might need to manually add :000 at the end of your date string for this to work.




回答2:


After half a day spent trying to resolve the same issue, I ended up dropping odbc and using dblib instead. I installed php7.0-sybase package, adapted the data source name of my PDO connection and resolved once for all. Now every bind is working.



来源:https://stackoverflow.com/questions/39044034/how-to-bind-iso8601-tsql-datetime-parameter-with-pdo

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!