Различия в типах данных между драйвером PHP sqlsrv и драйвером PDO - PullRequest
2 голосов
/ 21 апреля 2020

Здесь я использую 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" }

Если вы заметили, мне пришлось использовать cast(? as varchar(13)) в коде PDO. Без этого не вернулось бы ни одного ряда. На sqlsrv мне не нужно было использовать функцию CAST(). Почему это? Кроме того, столбец id в базе данных - это BINARY(13), так почему я должен приводить id к varchar, а не к binary (при двоичном приведении это тоже не не найти строку)?

1 Ответ

3 голосов
/ 21 апреля 2020

Почему значения даты и времени возвращаются по-разному?

Фактически это только настройка.

Когда вы используете PDO_SQLSRV (как упомянуто в документации), типы даты и времени (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 (снова из документации 1018 *), 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 Driver для SQL Сервер.

Как преобразовать значения параметров?

Использование в операторе функций CAST() и CONVERT(), и значение параметра привязки со строковым значением должно работать. Конечно, вы можете указать тип данных параметра при привязке параметра.

Для PDO_SQLSRV вы должны расширить синтаксис для PDOStatement :: bindParam () .

Для SQLSRV вы можете использовать расширенный синтаксис $params , чтобы указать тип данных SQL Server, когда вы делаете вызов sqlsrv_query()\sqlsrv_execute().

Я могу воспроизвести эту проблему (PHP 7.1.12, PHP Драйвер для SQL Сервер 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 

Таблица:

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

...
?> 
...