sqlsrv_query

(没有可用版本信息,可能只存在于 Git 中)

sqlsrv_query准备并执行查询

说明

sqlsrv_query(
    资源 $conn,
    字符串 $sql,
    数组 $params = ?,
    数组 $options = ?
): 混合

准备并执行查询。

参数

conn

sqlsrv_connect() 返回的连接资源。

sql

定义要准备和执行的查询的字符串。

params

在执行参数化查询时,指定参数信息的数组。数组元素可以是以下任何一种:

  • 文字值
  • PHP 变量
  • 具有以下结构的数组:array($value [, $direction [, $phpType [, $sqlType]]])
下表描述了上述数组结构中的元素

数组结构
元素 说明
$value 文字值、PHP 变量或 PHP 按引用传递的变量。
$direction (可选) 用于指示参数方向的以下 SQLSRV 常量之一:SQLSRV_PARAM_IN、SQLSRV_PARAM_OUT、SQLSRV_PARAM_INOUT。默认值为 SQLSRV_PARAM_IN。
$phpType (可选) 指定返回值的 PHP 数据类型的 SQLSRV_PHPTYPE_* 常量。
$sqlType (可选) 指定输入值的 SQL Server 数据类型的 SQLSRV_SQLTYPE_* 常量。
options

指定查询属性选项的数组。支持的键在下表中描述

查询选项
说明
QueryTimeout 一个正整数。 设置查询超时时间(以秒为单位)。默认情况下,驱动程序将无限期地等待结果。
SendStreamParamsAtExec truefalse(默认值为 true 配置驱动程序在执行时发送所有流数据(true),或以块发送流数据(false)。默认情况下,该值设置为 true。有关更多信息,请参阅 sqlsrv_send_stream_data()
Scrollable SQLSRV_CURSOR_FORWARD、SQLSRV_CURSOR_STATIC、SQLSRV_CURSOR_DYNAMIC 或 SQLSRV_CURSOR_KEYSET 请参阅 Microsoft SQLSRV 文档中的 » 指定游标类型和选择行

返回值

成功时返回一个语句资源,如果发生错误,则返回 false

示例

示例 #1 sqlsrv_query() 示例

<?php
$serverName
= "serverName\sqlexpress";
$connectionInfo = array( "Database"=>"dbName", "UID"=>"username", "PWD"=>"password" );
$conn = sqlsrv_connect( $serverName, $connectionInfo);
if(
$conn === false ) {
die(
print_r( sqlsrv_errors(), true));
}

$sql = "INSERT INTO Table_1 (id, data) VALUES (?, ?)";
$params = array(1, "some data");

$stmt = sqlsrv_query( $conn, $sql, $params);
if(
$stmt === false ) {
die(
print_r( sqlsrv_errors(), true));
}
?>

注意

对于您计划仅执行一次的语句,请使用 sqlsrv_query()。如果您打算使用不同的参数值重新执行语句,请使用 sqlsrv_prepare()sqlsrv_execute() 的组合。

参见

添加备注

用户贡献的备注 6 备注

28
bill_spam0001 at yahoo dot com
11 年前
如果您在尝试执行查询时遇到错误,并且 sqlsrv_errors(SQLSRV_ERR_ERRORS) 的输出是:

SQLSTATE: IMSSP
code: -14
message: An invalid parameter was passed to sqlsrv_query.

您未能传递有效的参数给 sqlsrv_query 本身,这可能是以下三个参数之一:
Connection:SQL Server 连接的有效句柄
Query:包含您的查询的有效字符串,其中包含参数占位符:“(?)”
Parameters:包含查询参数值的数组。(可选,但必须与查询中的占位符数量匹配。)

我找不到有关此错误的任何信息,事实证明是缺少连接参数。在我的情况下,我发现我在代码中键入了“$connn”而不是“$conn”
if ($stmt=sqlsrv_query($conn, $sql, $params)) { ...

虽然这似乎是完全的“菜鸟”行为,但事实是,关于此 SQL Server 错误消息本身的信息很少。因此,SQLSTATE“IMSSP”,CODE“-14”的含义是您没有向 sqlsrv_query 函数提供任何有效的连接对象。

此消息可能令人困惑,尤其是在页面上有几个 sqlsrv_query 出现的情况下,您可能在关闭连接后添加了一个新的出现。

由于我在正常的跟踪渠道上浪费了大量时间,我认为在这里引用此错误会提供一些帮助。我被“参数”困住了,并认为这是一个错误的参数对象,忽略了传递未定义的连接对象给 sqlsrv_query
15
vavra at 602 dot cz
6 年前
注意!
如果 sql 包含 INSERT、UPDATE 或 DELETE 语句,则必须使用受影响的行数。sqlsrv_query 返回一个 sql 游标,必须读取该游标以完成事务,前提是结果不是 false。对于 sqlsrv_execute 也是如此。在这种情况下,还必须使用准备好的语句句柄 $smt 读取游标。

另一种解决方案是在 sqlsrv 语句和所有调用的过程、函数和触发器顶部放置 SET NOCOUNT ON。

我们实际上已经观察到带有 500 个插入的 sql 语句,但只有 368 个插入没有返回 false。使用 SET NOCOUNT ON 或读取所有行的游标,所有行都被插入。

请参阅处理结果 (ODBC):https://docs.microsoft.com/en-us/sql/relational-databases/native-client-odbc-results/processing-results-odbc 每个 INSERT、UPDATE 和 DELETE 语句都返回一个结果集,其中只包含修改受影响的行数。当应用程序调用 SQLRowCount 时,此计数可用。ODBC 3.x 应用程序必须调用 SQLRowCount 以检索结果集或调用 SQLMoreResults 以取消它。当应用程序执行包含多个 INSERT、UPDATE 或 DELETE 语句的批处理或存储过程时,必须使用 SQLRowCount 处理每个修改语句的结果集,或者使用 SQLMoreResults 取消它。这些计数可以通过在批处理或存储过程中包含 SET NOCOUNT ON 语句来取消。
3
bill_spam0001 at yahoo dot com
12 年前
提示:这可能很明显,但你需要修剪你的字符串,使其适合你通过参数化查询或存储过程保存到数据库字段的字段。(例如:只向 VARCHAR(20) 数据库字段提交最多 20 个字符)。如果你发送的字符串大于查询可以处理的,你将收到错误。

在清理字符串时,你很可能会使用 php substr() 函数。正如文档所述,此函数在遇到空字符串时将返回布尔值 FALSE。不理会此布尔值 FALSE 将导致在你的数据库表中保存“0”,而不是空字符串。

由于修剪输入也很重要,因此针对此问题的简单直观的解决方案是修剪你的 substr() 输出,这将始终提供空字符串,而不是布尔值 FALSE。

因此这将始终有效
<?php
//trim last 返回空字符串,数据类型为字符串
$address_line_2 = trim(substr($_POST['addr2']),0,30));

echo
gettype($address_line_2); //输出 string

//执行数据库查询将在 field tblAddressBook.addr2 中保存 ""
$sql = "update tblAddressBook set name=(?), addr1=(?), addr2=(?),..."
$params = array($name, $address_line_1, $address_line_2, ...)
$sql_srv_query($db_conn, $sql, $params);

?>
第二种方法将在你的数据库中提供看似意外的数据。
<?php
//如果修剪后 post 变量的结果为空字符串 "",substr() 将返回 FALSE
$address_line_2 = substr(trim($_POST['addr2'])),0,30);

//$address_line_2 实际上 === FALSE,而不是 ""
echo gettype($address_line_2); //输出 boolean

//执行数据库查询将在 field tblAddressBook.addr2 中保存 "0"
$sql = "update tblAddressBook set name=(?), addr1=(?), addr2=(?),..."
$params = array($name, $address_line_1, $address_line_2, ...)
$sql_srv_query($db_conn, $sql, $params);

?>

你也可以使用以下方法将类型强制转换为字符串,
这将把布尔值 false 强制转换回预期的空字符串。
<?php

$address_line_2
= (string)substr(trim($_POST['addr2'])),0,30);

echo
gettype($address_line_2); //输出 string

//执行数据库查询将在 field tblAddressBook.addr2 中保存 ""
$sql = "update tblAddressBook set name=(?), addr1=(?), addr2=(?),..."
$params = array($name, $address_line_1, $address_line_2, ...)
$sql_srv_query($db_conn, $sql, $params);

?>

在切换到 IIS7、PHP 5.3.8 和 SQL Server 2008 之前,我没有注意到这种行为。但 IIS7、PHP 5.2 和 SQL Server 2008 也表现出这种行为。
2
oleg at mastak dot fi
11 年前
如果你在指定有效可滚动游标时遇到错误“[Microsoft][ODBC Driver Manager] Invalid cursor state”,请查看以下错误报告

https://bugs.php.net/bug.php?id=63498

目前存在一个错误,要求在相应数组中,可滚动选项必须在 QueryTimeout 之前指定。
-1
erikpsundberg at gmail dot com
4 年前
2 个工作示例

print "<h1>SQL 查询非 PDO</h1>";
print "<h2>连接</h2>";
$connectionInfo = array( "Database"=>$sql_database, "UID"=>$sql_username, "PWD"=>$sql_password );
$conn = sqlsrv_connect( $sql_server, $connectionInfo);

if( $conn === false ) {
die( print_r( sqlsrv_errors(), true));
} else {
print "良好 DB 连接:$conn<br>";
}

print "<h2>查询示例 1 | 通过关联数组获取</h2>";
$sql = "SELECT username, active FROM users WHERE username = '$username'";
print "SQL:$sql\n";
$result = sqlsrv_query($conn, $sql);
if($result === false) {
die(print_r(sqlsrv_errors(), true));
}
#通过数组获取数据
while($row = sqlsrv_fetch_array($result, SQLSRV_FETCH_ASSOC)) {
print_r($row);
}

print_line();
print "<h2>查询示例 2 | 注入保护 | 通过对象获取</h2>";
$sql = "SELECT username, active FROM users WHERE username = ?";
print "SQL:$sql\n";
$result = sqlsrv_query($conn, $sql, array($username));
if($result === false) {
die(print_r(sqlsrv_errors(), true));
}
#通过对象获取数据
while($row = sqlsrv_fetch_object($result)) {
print_r($row);
}

--------------------------------------------------
结果

连接
良好 DB 连接:资源 ID #2
查询示例 1 | 通过关联数组获取
SQL:SELECT username, active FROM users WHERE username = 'admin'
数组
(
[username] => admin
[active] => 1
)
######################################################################
查询示例 2 | 注入保护 | 通过对象获取
SQL:SELECT username, active FROM users WHERE username = ?
stdClass 对象
(
[username] => admin
[active] => 1
)
-2
anon at example dot com
5 年前
请注意,你可以在执行单个查询时获得多个结果,例如

<?php
$stmt
= sqlsrv_query($conn, "use dbname; select 1");
?>

在 tsql 或管理工作室中运行相同的查询将按预期工作。但是,使用 sqlsrv_* 函数,这将为你提供两个结果集——一个用于“use”,另一个用于“select”。

<?php
//将结果指针从 "use" 提升到 "select"
sqlsrv_next_result($stmt);

//现在你可以读取 "1"
print_r(sqlsrv_fetch_array($stmt));
?>

对于从创建/填充临时表开始的复杂查询,你需要将结果指针提升到这些语句,以从最终的 select 语句中获取数据。在旧版本的 PHP(至少使用基于 FreeTDS 的 mssql 连接)中,你只会获得最后一个结果,因此无需考虑这一点。
To Top