PHP PDO:SQLSRV/SQLSRV连接MS SQL执行复合SQL无结果求助
问题分析与解决方案
你的问题核心在于:你的SQL语句会返回多个结果集,而PHP的两个SQL Server扩展默认只会处理第一个结果集,导致了不同的异常表现:
- PDO_SQLSRV的第一个结果集是
INSERT操作的影响行数(没有字段),调用fetch()时就会抛出"The active result for the query contains no fields"错误; - SQLSRV扩展同样只处理第一个结果集(无有效数据),所以
sqlsrv_fetch_array()拿不到内容,自然没有输出。
而SQL Server Management Studio会自动解析并展示所有结果集,所以你能正常看到返回数据。
针对PDO_SQLSRV的修改方案
你需要手动遍历所有结果集,跳过没有字段的结果集,直到获取到包含数据的那个结果集:
<?php try { $db = new PDO("sqlsrv:Server=sql_server;Database=database", "username", "password"); $db->setAttribute(PDO::ATTR_ERRMODE,PDO::ERRMODE_EXCEPTION); $test = $db->prepare('declare @t2 code.instancereferencestable; insert into @t2 select top 10 [Instance Reference] from imported.instance where [Instance Type] = \'CENAS\' and [Instance Reference] = \'CENAS.8000\' order by [Instance (Id)] desc; select * from transformed.attribute_instance_extended_from_references(@t2)'); $test->execute(); // 遍历所有结果集,筛选出有数据的结果 do { if ($test->columnCount() > 0) { // 处理有效结果集 $result = $test->fetch(PDO::FETCH_OBJ); print_r($result); } } while ($test->nextRowset()); echo "Connected!". "\n"; } catch(Exception $e) { echo "Error: " . $e->getMessage() . "\n"; } ?>
关键逻辑是用columnCount()判断当前结果集是否包含字段,并用nextRowset()切换到下一个结果集。
针对SQLSRV扩展的修改方案
同样需要手动切换到下一个结果集,因为第一个结果集是INSERT的执行状态,第二个才是你需要的查询结果:
<?php $serverName = "sql_server"; $connectionOptions = array( "Database" => "database", "Uid" => "username", "PWD" => "password" ); $conn = sqlsrv_connect($serverName, $connectionOptions); if ( $conn ) { echo "Connection established.".PHP_EOL; $sql = ("declare @t2 code.instancereferencestable; insert into @t2 select top 10 [Instance Reference] from imported.instance where [Instance Type] = 'CENAS' and [Instance Reference] = 'CENAS.8000' order by [Instance (Id)] desc; select * from transformed.attribute_instance_extended_from_references(@t2);"); $stmt = sqlsrv_query($conn, $sql); if ( $stmt === false ) { die( print_r( sqlsrv_errors(), true)); } else { // 跳过第一个无数据的结果集(INSERT操作的返回) sqlsrv_next_result($stmt); // 循环获取第二个结果集的所有数据 while ($row = sqlsrv_fetch_array($stmt, SQLSRV_FETCH_ASSOC)) { print_r ($row); } } } else { echo "Connection could not be established.".PHP_EOL; die( print_r( sqlsrv_errors(), true)).PHP_EOL; } ?>
这里用sqlsrv_next_result()切换到第二个结果集,再循环读取所有数据。
额外提示
如果你的SQL语句中包含多个SELECT、存储过程调用这类会返回结果的操作,都需要注意处理多结果集的情况。两个扩展都不会自动跳过无数据的结果集,必须手动处理。
内容的提问来源于stack exchange,提问作者CFRR
相关产品推荐
相关产品推荐

