Pat*_*ric 2 php sql-server sqlsrv
我们必须升级系统以使用 PHP7.3(从 MSSQL 更改为 SQLSRV DB Driver 和带有 PDO 的 SQLSRV)
我的问题是,我不理解这种行为以及如何正确解决它。
当我从数据库查询一DateTime列时,我得到:
2019-03-26 00:00:00.000
Run Code Online (Sandbox Code Playgroud)
当我尝试将相同的值存储到DateTime数据库的列中时,它不起作用。我的数据库接受这种格式,例如:
26-03-2019 00:00:00.000
Run Code Online (Sandbox Code Playgroud)
因此,我们现有的数据库层无法正常工作。
我需要帮助来理解这种行为,以及如何告诉数据库使用相同的格式进行查询和插入/更新
我们使用的查询没有特殊的转换,简单的 SELECT / UPDATE / INSERT。
PHP 版本:PHP 7.3.3-1+ubuntu18.04.1+deb.sury.org+1 (cli)(构建时间:2019 年 3 月 7 日 20:31:49)(NTS)
版权所有 (c) 1997-2018 The PHP Group Zend Engine v3.3.3,版权所有 (c) 1998-2018 Zend Technologies 与 Zend OPcache v7.3.3-1+ubuntu18.04.1+deb.sury.org+1,版权所有 (c) 1999-2018,作者:Zend Technologies
SQL服务器:MSSQL服务器2014
谢谢任何提示
1. 如何从 SQL Server 检索日期和时间值:
\n1.1. 使用 PHP Driver for SQL Server 的 PDO_SQLSRV 版本从 SQL Server 检索日期和时间值:
\n当您使用 PDO_SQLSRV 驱动程序时,日期和时间列中的值在驱动程序版本 5.6.0 之前以字符串形式返回。在这种情况下,唯一的选择是重新格式化日期和时间值(例如从\'2019-03-26 00:00:00.000\'到)。\'26-03-2019 00:00:00.000\'从版本 5.6.0 开始,您可以使用PDO::SQLSRV_ATTR_FETCHES_DATETIME_TYPE连接或语句属性更改此行为,并以 PHP DateTime 变量的形式检索日期和时间值。然后,您可以使用DateTime::format轻松地将此变量格式化为字符串。
<?php\n\n// Connection\n$server = "server\\instanse";\n$database = "database";\n$username = "username";\n$password = "password";\n\n$conn = new PDO("sqlsrv:server=$server;Database=$database", $username, $password);\n$conn->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);\n$conn->setAttribute(PDO::SQLSRV_ATTR_ENCODING, PDO::SQLSRV_ENCODING_SYSTEM);\n\n// Datetime values as PHP DateTime object\n$query = "SELECT GETDATE() AS DateTimeColumn";\n$stmt = $conn->prepare($query);\n$stmt->setAttribute(PDO::SQLSRV_ATTR_FETCHES_DATETIME_TYPE, true);\n$stmt->execute();\n\nwhile ($row = $stmt->fetch(PDO::FETCH_ASSOC)) { \n echo $row["DateTimeColumn"]->format(\'Y-m-d H:i:s.v\') . "<br>";\n}\n$stmt = null;\n\n// Datetime values as text\n$query = "SELECT GETDATE() AS DateTimeColumn";\n$stmt = $conn->prepare($query);\n$stmt->setAttribute(PDO::SQLSRV_ATTR_FETCHES_DATETIME_TYPE, false);\n$stmt->execute();\nwhile ($row = $stmt->fetch(PDO::FETCH_ASSOC)) { \n echo $row["DateTimeColumn"] . "<br>";\n}\n$stmt = null;\n\n// End\n$conn = null;\n\n?>\nRun Code Online (Sandbox Code Playgroud)\n1.2. 使用 PHP Driver for SQL Server 的 PDO_SQLSRV 版本从 SQL Server 存储过程检索输出参数的日期和时间值:
\n文档中的注释解释说,PDO::SQLSRV_ATTR_FETCHES_DATETIME_TYPE 连接或语句属性仅适用于日期和时间类型的常规获取,因为无法将 DateTime 对象指定为输出参数。在这种情况下,唯一可能的选择是将存储过程的日期时间输出参数作为 PHP 字符串变量传递。返回值取决于会话的语言环境。
存储过程:
\nCREATE PROCEDURE spReturnDateTime\n @datetime datetime OUTPUT\nAS\nBEGIN\n SET NOCOUNT ON\n SELECT GETDATE() AS [DateTime]\n SET @datetime = GETDATE()\nEND\nRun Code Online (Sandbox Code Playgroud)\nPHP:
\n<?php\n// Connnection\n$server = "server\\instanse";\n$database = "database";\n$username = "username";\n$password = "password";\n\n$conn = new PDO("sqlsrv:server=$server;Database=$database", $username, $password);\n$conn->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);\n$conn->setAttribute(PDO::SQLSRV_ATTR_ENCODING, PDO::SQLSRV_ENCODING_SYSTEM);\n\n// Output parameters from stored procedure\n// \n$sql = "\n SET LANGUAGE \'English\'\n EXEC :errcode = spReturnDateTime @datetime = :datetime\n";\n$errcode = 0;\n$datetime = "";\n$stmt = $conn->prepare($sql);\n$stmt->bindParam(\':errcode\', $errcode, PDO::PARAM_INT | PDO::PARAM_INPUT_OUTPUT, PDO::SQLSRV_PARAM_OUT_DEFAULT_SIZE);\n$stmt->bindParam(\':datetime\', $datetime, PDO::PARAM_STR | PDO::PARAM_INPUT_OUTPUT, 50);\n$stmt->execute();\ndo {\n while ($row = $stmt->fetch( PDO::FETCH_ASSOC) ){\n echo $row["DateTime"]."<br>";\n }\n} while ($stmt->nextRowset()); \n$stmt = null;\necho $datetime."<br>";\n//\n$sql = "\n SET LANGUAGE \'Bulgarian\'\n EXEC :errcode = spReturnDateTime @datetime = :datetime\n";\n$errcode = 0;\n$datetime = "";\n$stmt = $conn->prepare($sql);\n$stmt->bindParam(\':errcode\', $errcode, PDO::PARAM_INT | PDO::PARAM_INPUT_OUTPUT, PDO::SQLSRV_PARAM_OUT_DEFAULT_SIZE);\n$stmt->bindParam(\':datetime\', $datetime, PDO::PARAM_STR | PDO::PARAM_INPUT_OUTPUT, 50);\n$stmt->execute();\ndo {\n while ($row = $stmt->fetch( PDO::FETCH_ASSOC) ){\n echo $row["DateTime"]."<br>";\n }\n} while ($stmt->nextRowset()); \n$stmt = null;\necho $datetime."<br>";\n\n// End\n$conn = null;\nRun Code Online (Sandbox Code Playgroud)\n结果:
\n2021-06-10 10:05:54.580\nJun 10 2021 10:05AM\n2021-06-10 10:05:54.580\n\xd1\x8e\xd0\xbd\xd0\xb8 10 2021 10:05AM\nRun Code Online (Sandbox Code Playgroud)\n1.3. 使用 PHP Driver for SQL Server 的 SQLSRV 版本从 SQL Server 检索日期和时间值:
\n默认情况下,smalldatetime、datetime、date、time、datetime2 和 datetimeoffset 类型将作为 PHP DateTime 对象返回,但可以通过\'ReturnDatesAsStrings\'在连接字符串或语句级别设置选项来更改此行为:
<?php\n\n// Connection\n$server = "server\\instanse";\n$database = "database";\n$username = "username";\n$password = "password";\n\n$cinfo = array(\n "Database" => $database, \n "UID" => $username, \n "PWD" => $password\n);\n$conn = sqlsrv_connect($server, $cinfo);\nif ($conn === false) {\n echo "Error (sqlsrv_connect): ".print_r(sqlsrv_errors(), true);\n exit;\n}\n\n// Datetime values as PHP DateTime object\n$query = "SELECT GETDATE() AS DateTimeColumn";\n$options = array(\'ReturnDatesAsStrings\' => false);\n$stmt = sqlsrv_query($conn, $query, null, $options);\nif ($stmt === false) {\n echo "Error (sqlsrv_query): ".print_r(sqlsrv_errors(), true);\n exit;\n}\nwhile ($row = sqlsrv_fetch_array($stmt, SQLSRV_FETCH_ASSOC)) {\n echo $row["DateTimeColumn"]->format(\'Y-m-d H:i:s.v\') . "<br>";\n}\nsqlsrv_free_stmt($stmt);\n\n// Datetime values as text\n$query = "SELECT GETDATE() AS DateTimeColumn";\n$options = array(\'ReturnDatesAsStrings\' => true);\n$stmt = sqlsrv_query($conn, $query, null, $options);\nif ($stmt === false) {\n echo "Error (sqlsrv_query): ".print_r(sqlsrv_errors(), true);\n exit;\n}\nwhile ($row = sqlsrv_fetch_array($stmt, SQLSRV_FETCH_ASSOC)) {\n echo $row["DateTimeColumn"] . "<br>";\n}\nsqlsrv_free_stmt($stmt);\n\n// End\nsqlsrv_close($conn);\n\n?>\nRun Code Online (Sandbox Code Playgroud)\n1.4. 使用 MSSQL PHP 扩展从 SQL Server 检索日期和时间值(该扩展在 PHP 7.0.0 中已删除):
\n当您使用 MSSQL 扩展时,日期和时间值以文本形式返回,但格式取决于文件mssql.datetimeconvert中的设置php.ini。当此选项为 时ON,日期和时间值将根据 SQL Server 设置进行转换,并且何时将OFF日期和时间值转换为YYYY-MM-DD hh:mm:ss格式。
<?php\n$server = "server\\instanse";\n$database = "database";\n$username = "username";\n$password = "password";\n\n$conn = mssql_connect($server);\nif ($conn === false) {\n echo "Error (mssql_connect): ".mssql_get_last_message();\n exit;\n}\nmssql_select_db($database, $conn);\n\n$query = "SELECT DateTimeColumn FROM OneTable";\n$stmt = mssql_query($sql, $conn);\nif ($stmt === false) {\n echo "Error (mssql_query): ".mssql_get_last_message();\n exit;\n}\n\nwhile ($row = mssql_fetch_assoc($stmt)) {\n echo print_r($row, true);\n}\n\nmssql_free_result($stmt);\nmssql_close($conn);\n?>\nRun Code Online (Sandbox Code Playgroud)\n作为附加说明,此设置似乎ON在您的服务器环境中,因为您可以发送日期,而\'26-03-2019 00:00:00.000\'不会出现错误。
2. 如何将日期和时间值传递给 SQL Server:
\n作为一般规则,可以使用明确的日期时间格式 (yyyymmdd或yyyy-mm-ddThh:mm:ss) 和参数化语句将日期和时间值传递到 SQL Server。
2.1. 使用 PHP Driver for SQL Server 的 PDO_SQLSRV 版本将日期和时间值传递到 SQL Server:
\n<?php\n$server = "server\\instanse";\n$database = "database";\n$username = "username";\n$password = "password";\n\n$conn = new PDO("sqlsrv:server = $server; Database = $database", $username, $password);\n$conn->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);\n\n$query = "INSERT INTO OneTable (DateTimeColumn) VALUES (?)";\n$datetime = (new DateTime())->format("Y-m-d\\TH:i:s");\n$stmt = $conn->prepare($query);\n$stmt->bindParam(1, $datetime);\n$stmt->execute();\n\n$stmt = null;\n$conn = null;\n?>\nRun Code Online (Sandbox Code Playgroud)\n2.2. 使用 PHP Driver for SQL Server 的 SQLSRV 版本将日期和时间值传递到 SQL Server:
\n使用此版本的驱动程序,您可以使用扩展参数语法并将日期时间值作为 PHP DateTime 对象传递,其中包含有关参数的 PHP 和 SQL Server 数据类型的信息。
\n<?php\n$server = "server\\instanse";\n$database = "database";\n$username = "username";\n$password = "password";\n\n$cinfo = array(\n "Database" => $database, \n "UID" => $username, \n "PWD" => $password\n);\n$conn = sqlsrv_connect($server, $cinfo);\nif ($conn === false) {\n echo "Error (sqlsrv_connect): ".print_r(sqlsrv_errors(), true);\n exit;\n}\n\n$query = "INSERT INTO OneTable (DateTimeColumn) VALUES (?)";\n$datetime = new DateTime();\n$params = array(\n array($datetime, SQLSRV_PARAM_IN, SQLSRV_PHPTYPE_DATETIME, SQLSRV_SQLTYPE_DATETIME)\n); \n// or as usual, pass datetime values as text\n//$params = array($datetime->format("Y-m-d\\TH:i:s")); \n$stmt = sqlsrv_query($conn, $query, $params);\nif ($stmt === false) {\n echo "Error (sqlsrv_query): ".print_r(sqlsrv_errors(), true);\n exit;\n}\n\nsqlsrv_free_stmt($stmt);\nsqlsrv_close($conn);\n?>\nRun Code Online (Sandbox Code Playgroud)\n