为啥 NULL 左外连接使用 sqlsrv_fetch_array 在 PHP 中停止数据集导航?
Posted
技术标签:
【中文标题】为啥 NULL 左外连接使用 sqlsrv_fetch_array 在 PHP 中停止数据集导航?【英文标题】:Why do NULL left outer joins stop dataset navigation in PHP with sqlsrv_fetch_array?为什么 NULL 左外连接使用 sqlsrv_fetch_array 在 PHP 中停止数据集导航? 【发布时间】:2014-03-21 03:13:15 【问题描述】:我正在将 ColdFusion 站点转换为 php,但遇到了 LEFT OUTER JOIN 和 PHP SQL 驱动程序的问题。基本上,如果你离开外连接一个不返回结果的表,然后尝试循环主表,它会在遇到数据集中的第一个空连接结果时停止。
使用
PHP 5.3.27、php_sqlsrv_53_nts_vc9.dll、SQL Server 2005
CREATE TABLE [dbo].[IS_MAIN_TABLE](
[iMainRow] [int] NULL,
[sMainText] [varchar](50) NULL,
[iSubRowID] [int] NULL
)
CREATE TABLE [dbo].[IS_SUB_TABLE](
[iSubRow] [int] NULL,
[sSubText] [varchar](50) NULL
)
INSERT INTO IS_MAIN_TABLE(iMainRow,sMainText,iSubRowID) VALUES (1,'One',1);
INSERT INTO IS_MAIN_TABLE(iMainRow,sMainText,iSubRowID) VALUES (2,'Two',NULL);
INSERT INTO IS_MAIN_TABLE(iMainRow,sMainText,iSubRowID) VALUES (3,'Three',3);
INSERT INTO IS_MAIN_TABLE(iMainRow,sMainText,iSubRowID) VALUES (4,'Four',NULL);
INSERT INTO IS_MAIN_TABLE(iMainRow,sMainText,iSubRowID) VALUES (5,'Five',5);
INSERT INTO IS_SUB_TABLE(iSubRow,sSubText) VALUES (1,'Sub One');
INSERT INTO IS_SUB_TABLE(iSubRow,sSubText) VALUES (2,'Sub Two');
INSERT INTO IS_SUB_TABLE(iSubRow,sSubText) VALUES (3,'Sub Three');
INSERT INTO IS_SUB_TABLE(iSubRow,sSubText) VALUES (4,'Sub Four');
INSERT INTO IS_SUB_TABLE(iSubRow,sSubText) VALUES (5,'Sub Five');
现在在 Studio 中使用连接运行此选择会提供以下 5 行结果:
SELECT * FROM IS_MAIN_TABLE LEFT OUTER JOIN IS_SUB_TABLE ON IS_SUB_TABLE.iSubRow = IS_MAIN_TABLE.iSubRowID;
1 One 1 1 Sub One
2 Two NULL NULL NULL
3 Three 3 3 Sub Three
4 Four NULL NULL NULL
5 Five 5 5 Sub Five
然后为相同的 SQL 语句运行这个 PHP 代码:
<?php
function get_error()
$errors = sqlsrv_errors();
$errtxt = "Error occured: ";
foreach( $errors as $error)
$errtxt .= $error["SQLSTATE"] . ", ";
$errtxt .= $error["code"] . ", ";
$errtxt .= $error["message"] . "<br>";
return $errtxt;
$sitedbserver = "SERVERHERE";
$sitedbuser = "userhere";
$sitedbpassword = "pwdhere";
$sitedbinstance = "INSTANCEHERE";
$sitedbconnection = array( "Database"=>$sitedbinstance, "UID"=>$sitedbuser, "PWD"=>$sitedbpassword);
$dbhandle = sqlsrv_connect($sitedbserver, $sitedbconnection) or die("Couldn't connect to SQL Server");
if(!$dbhandle)
echo 'Database connection failed...';
exit;
else
//do something
$sql = <<<EOSQL
SELECT * FROM IS_MAIN_TABLE LEFT OUTER JOIN IS_SUB_TABLE ON IS_SUB_TABLE.iSubRow = IS_MAIN_TABLE.iSubRowID;
EOSQL;
$result = sqlsrv_query($dbhandle, $sql,array(), array( "Scrollable" => SQLSRV_CURSOR_KEYSET ));
$numRows = sqlsrv_num_rows($result);
if ($numRows <> 0)
echo '<table id="simplegrid" cellpadding="0" cellspacing="0" >';
while($row = sqlsrv_fetch_array($result, SQLSRV_FETCH_ASSOC))
// if($row===false) die(get_error());
echo '<tr><td>' . $row['sMainText'] . '</td><td>' . $row['sSubText'] . '</td></tr>';
echo '</table>';
?>
我只得到第一行。
One Sub One
如果我更改 SQL 以排除 NULL...
$sql = <<<EOSQL
SELECT * FROM IS_MAIN_TABLE
LEFT OUTER JOIN IS_SUB_TABLE ON IS_SUB_TABLE.iSubRow = IS_MAIN_TABLE.iSubRowID
WHERE iSubRow IS NOT NULL;
EOSQL;
我得到了三行
One Sub One
Three Sub Three
Five Sub Five
在循环中取消注释 get_error 调用只会在第一行返回一个“0”,这并没有多大帮助。我希望结果实际上与在分析器/工作室中运行查询相同,但没有骰子。我遇到了连接表为空的情况,并且在处理过程中创建了一个条件,让某人知道屏幕上的数据丢失等......所以我必须找到一种方法来处理这个问题,但我现在只是难住了。我不确定将潜在的空字段合并到 '' 是否值得麻烦,或者是否有办法让空值在 PHP、驱动程序、SQL 级别默认为 ''。
【问题讨论】:
【参考方案1】:我找到了解决办法。我不期待对所有现有查询进行重组,但似乎使用 PDO 和 PDO 驱动程序可以正确处理空连接表。使用上面相同的表/数据,但使用此代码针对 php_pdo_sqlsrv_53_nts_vc9.dll ...
try
$conn = new PDO( "sqlsrv:server=$sitedbserver ; Database=$sitedbinstance", "$sitedbuser", "$sitedbpassword");
$conn->setAttribute( PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION );
catch(Exception $e)
die( print_r( $e->getMessage() ) );
$tsql = <<<EOSQL
SELECT * FROM IS_MAIN_TABLE
LEFT OUTER JOIN IS_SUB_TABLE ON IS_SUB_TABLE.iSubRow = IS_MAIN_TABLE.iSubRowID;
EOSQL;
$getProducts = $conn->prepare($tsql);
$getProducts->execute();
$products = $getProducts->fetchAll(PDO::FETCH_ASSOC);
$productCount = count($products);
if($productCount > 0)
echo '<table id="simplegrid" cellpadding="0" cellspacing="0" >';
foreach( $products as $row )
echo '<tr><td>' . $row['sMainText'] . '</td><td>' . $row['sSubText'] . '</td></tr>';
echo '</table>';
我得到了预期的响应:
One Sub One
Two
Three Sub Three
Four
Five Sub Five
我想我不应该关心为什么非 PDO 解决方案现在不起作用,因为我有一个解决方案,但是如果有人遇到这种情况并且可以阐明我很感激关闭的原因。
【讨论】:
以上是关于为啥 NULL 左外连接使用 sqlsrv_fetch_array 在 PHP 中停止数据集导航?的主要内容,如果未能解决你的问题,请参考以下文章