PHP sqlsrv 驱动程序和 PDO 驱动程序之间的数据类型差异
Data type differences between PHP sqlsrv driver and PDO driver
这里我用的是sqlsrv
:
$conn = sqlsrv_connect("192.168.1.102,1433", array("Database"=>"RF_User", "UID"=>"rfo-gcp", "PWD" => ""));
$tsql = "SELECT birthdate FROM tbl_rfaccount WHERE id = ?";
$stmt = sqlsrv_query($conn, $tsql, array("test"));
$result = sqlsrv_fetch_array($stmt);
var_dump($result);
结果:array(2) { [0]=> object(DateTime)#1 (3) { ["date"]=> string(26) "2020-04-19 20:40:00.000000" ["timezone_type"]=> int(3) ["timezone"]=> string(3) "UTC" } ["birthdate"]=> object(DateTime)#1 (3) { ["date"]=> string(26) "2020-04-19 20:40:00.000000" ["timezone_type"]=> int(3) ["timezone"]=> string(3) "UTC" } }
这里我用的是PDO
:
$conn = new PDO("sqlsrv:Server=192.168.1.102,1433; Database=RF_User;", "rfo-gcp", "");
$tsql = "SELECT birthdate FROM tbl_rfaccount WHERE id = cast(? as varchar(13))";
$stmt = $conn->prepare($tsql);
$stmt->execute(array("test"));
$result = $stmt->fetch(PDO::FETCH_ASSOC);
var_dump($result);
结果:array(1) { ["birthdate"]=> string(19) "2020-04-19 20:40:00" }
如果您注意到,我不得不在 PDO
代码上使用 cast(? as varchar(13))
。没有它就不会 return 任何行。在 sqlsrv
上,我不必使用 CAST()
函数。为什么是这样?此外,数据库中的 id
列是 BINARY(13)
,那么为什么我必须将 id
转换为 varchar
并且不 binary
(二进制转换也找不到该行)?
为什么返回的日期和时间值不同?
其实这只是一个设定。
当您使用 PDO_SQLSRV(文档中的 mentioned)时,日期和时间类型(smalldatetime、datetime、 date、time、datetime2 和 datetimeoffset)默认情况下作为字符串返回。 PDO::ATTR_STRINGIFY_FETCHES 和 PDO::SQLSRV_ATTR_FETCHES_NUMERIC_TYPE 属性都没有任何效果。为了将日期和时间类型检索为 PHP DateTime 对象,请将连接或语句属性 PDO::SQLSRV_ATTR_FETCHES_DATETIME_TYPE 设置为 true(默认情况下为 false)。
当你使用SQLSRV驱动程序时(再次来自documentation),smalldatetime, datetime, date, time, datetime2和 datetimeoffset 类型将作为 PHP DateTime 对象 返回。可以通过在连接字符串或语句级别设置 'ReturnDatesAsStrings'
选项来更改此行为。
$conn = sqlsrv_connect(
"192.168.1.102,1433",
array(
"ReturnDatesAsStrings"=>true,
"Database"=>"RF_User",
"UID"=>"rfo-gcp",
"PWD" => ""
)
);
请注意,某些功能取决于 PHP 用于 SQL 服务器的驱动程序的版本。
如何转换参数值?
在语句中使用 CAST()
和 CONVERT()
函数并将参数值与字符串值绑定应该可以。当然,您可以在绑定参数时指定参数数据类型。
对于 PDO_SQLSRV 你应该扩展 PDOStatement::bindParam() 的语法。
对于 SQLSRV 你可以使用扩展的 $params
syntax 来指定 SQL 服务器数据类型,当你打电话给 sqlsrv_query()\sqlsrv_execute()
.
我能够重现此问题(PHP 7.1.12,PHP SQL Server 4.3.0+9904 的驱动程序,SQL Server 2012)解决方案是使用:
$params = array($id, SQLSRV_PARAM_IN, null, SQLSRV_SQLTYPE_BINARY); // SQLSRV
$stmt->bindParam(1, $id, PDO::PARAM_LOB, null, PDO::SQLSRV_ENCODING_BINARY); // PDO_SQLSRV
Table:
CREATE TABLE tbl_rfaccount (id binary(13), birthdate datetime)
INSERT INTO tbl_rfaccount (id, birthdate) VALUES (CONVERT(binary(13), 'Test'), GETDATE())
PHP:
<?php
...
//
$id = "Test";
// SQLSRV
$tsql = "SELECT birthdate FROM tbl_rfaccount WHERE id = ?";
$params = array($id, SQLSRV_PARAM_IN, null, SQLSRV_SQLTYPE_BINARY);
$stmt = sqlsrv_query($conn, $tsql, $params);
if ($stmt === false) {
echo "Error (sqlsrv_query): ".print_r(sqlsrv_errors(), true);
exit;
}
$result = sqlsrv_fetch_array($stmt, SQLSRV_FETCH_ASSOC);
var_dump($result);
// PDO_SQLSRV
$tsql = "SELECT birthdate FROM tbl_rfaccount WHERE id = ?";
$stmt = $conn->prepare($tsql);
$stmt->bindParam(1, $id, PDO::PARAM_LOB, null, PDO::SQLSRV_ENCODING_BINARY);
$stmt->execute();
$result = $stmt->fetch(PDO::FETCH_ASSOC);
var_dump($result);
...
?>
这里我用的是sqlsrv
:
$conn = sqlsrv_connect("192.168.1.102,1433", array("Database"=>"RF_User", "UID"=>"rfo-gcp", "PWD" => ""));
$tsql = "SELECT birthdate FROM tbl_rfaccount WHERE id = ?";
$stmt = sqlsrv_query($conn, $tsql, array("test"));
$result = sqlsrv_fetch_array($stmt);
var_dump($result);
结果:array(2) { [0]=> object(DateTime)#1 (3) { ["date"]=> string(26) "2020-04-19 20:40:00.000000" ["timezone_type"]=> int(3) ["timezone"]=> string(3) "UTC" } ["birthdate"]=> object(DateTime)#1 (3) { ["date"]=> string(26) "2020-04-19 20:40:00.000000" ["timezone_type"]=> int(3) ["timezone"]=> string(3) "UTC" } }
这里我用的是PDO
:
$conn = new PDO("sqlsrv:Server=192.168.1.102,1433; Database=RF_User;", "rfo-gcp", "");
$tsql = "SELECT birthdate FROM tbl_rfaccount WHERE id = cast(? as varchar(13))";
$stmt = $conn->prepare($tsql);
$stmt->execute(array("test"));
$result = $stmt->fetch(PDO::FETCH_ASSOC);
var_dump($result);
结果:array(1) { ["birthdate"]=> string(19) "2020-04-19 20:40:00" }
如果您注意到,我不得不在 PDO
代码上使用 cast(? as varchar(13))
。没有它就不会 return 任何行。在 sqlsrv
上,我不必使用 CAST()
函数。为什么是这样?此外,数据库中的 id
列是 BINARY(13)
,那么为什么我必须将 id
转换为 varchar
并且不 binary
(二进制转换也找不到该行)?
为什么返回的日期和时间值不同?
其实这只是一个设定。
当您使用 PDO_SQLSRV(文档中的 mentioned)时,日期和时间类型(smalldatetime、datetime、 date、time、datetime2 和 datetimeoffset)默认情况下作为字符串返回。 PDO::ATTR_STRINGIFY_FETCHES 和 PDO::SQLSRV_ATTR_FETCHES_NUMERIC_TYPE 属性都没有任何效果。为了将日期和时间类型检索为 PHP DateTime 对象,请将连接或语句属性 PDO::SQLSRV_ATTR_FETCHES_DATETIME_TYPE 设置为 true(默认情况下为 false)。
当你使用SQLSRV驱动程序时(再次来自documentation),smalldatetime, datetime, date, time, datetime2和 datetimeoffset 类型将作为 PHP DateTime 对象 返回。可以通过在连接字符串或语句级别设置 'ReturnDatesAsStrings'
选项来更改此行为。
$conn = sqlsrv_connect(
"192.168.1.102,1433",
array(
"ReturnDatesAsStrings"=>true,
"Database"=>"RF_User",
"UID"=>"rfo-gcp",
"PWD" => ""
)
);
请注意,某些功能取决于 PHP 用于 SQL 服务器的驱动程序的版本。
如何转换参数值?
在语句中使用 CAST()
和 CONVERT()
函数并将参数值与字符串值绑定应该可以。当然,您可以在绑定参数时指定参数数据类型。
对于 PDO_SQLSRV 你应该扩展 PDOStatement::bindParam() 的语法。
对于 SQLSRV 你可以使用扩展的 $params
syntax 来指定 SQL 服务器数据类型,当你打电话给 sqlsrv_query()\sqlsrv_execute()
.
我能够重现此问题(PHP 7.1.12,PHP SQL Server 4.3.0+9904 的驱动程序,SQL Server 2012)解决方案是使用:
$params = array($id, SQLSRV_PARAM_IN, null, SQLSRV_SQLTYPE_BINARY); // SQLSRV
$stmt->bindParam(1, $id, PDO::PARAM_LOB, null, PDO::SQLSRV_ENCODING_BINARY); // PDO_SQLSRV
Table:
CREATE TABLE tbl_rfaccount (id binary(13), birthdate datetime)
INSERT INTO tbl_rfaccount (id, birthdate) VALUES (CONVERT(binary(13), 'Test'), GETDATE())
PHP:
<?php
...
//
$id = "Test";
// SQLSRV
$tsql = "SELECT birthdate FROM tbl_rfaccount WHERE id = ?";
$params = array($id, SQLSRV_PARAM_IN, null, SQLSRV_SQLTYPE_BINARY);
$stmt = sqlsrv_query($conn, $tsql, $params);
if ($stmt === false) {
echo "Error (sqlsrv_query): ".print_r(sqlsrv_errors(), true);
exit;
}
$result = sqlsrv_fetch_array($stmt, SQLSRV_FETCH_ASSOC);
var_dump($result);
// PDO_SQLSRV
$tsql = "SELECT birthdate FROM tbl_rfaccount WHERE id = ?";
$stmt = $conn->prepare($tsql);
$stmt->bindParam(1, $id, PDO::PARAM_LOB, null, PDO::SQLSRV_ENCODING_BINARY);
$stmt->execute();
$result = $stmt->fetch(PDO::FETCH_ASSOC);
var_dump($result);
...
?>