使用多个 foreach 循环时多次使用 PDO 语句
Posted
技术标签:
【中文标题】使用多个 foreach 循环时多次使用 PDO 语句【英文标题】:Use PDO statement multiple times when using multiple foreach loops 【发布时间】:2016-07-25 12:21:49 【问题描述】:我有以下代码:
if(!empty($postCountryAdd))
$sqlQueryLocalityAdd = $dbh->prepare("SELECT DISTINCT locality_add FROM table WHERE country_add = :country_add ORDER BY locality_add ASC");
$sqlQueryLocalityAdd->execute(array(':country_add' => $postCountryAdd));
echo '<option value="">Select locality</option>';
foreach($sqlQueryLocalityAdd as $localityAddRow)
//while ($localityAddRow = $sqlQueryLocalityAdd->fetch())
echo '<option value="';
echo $localityAddRow["locality_add"];
echo '">';
echo $localityAddRow["locality_add"];
echo '</option>';
如果我使用foreach($sqlQueryLocalityAdd as $localityAddRow)
,代码将停止响应。为什么我不能多次使用 foreach?请问怎么解决?
【问题讨论】:
也许很有趣?指出可滚动游标在 mysql 中不可用。 ***.com/a/19076778/3184785. 您的示例代码不会失败,因为它没有显示您有多个 foreach 块在彼此之后的情况——这就是人们感到困惑的原因。代码不会在整个结果集的第一次迭代中停止,否则您会尝试第二次完整迭代。 【参考方案1】:$sqlQueryLocalityAdd
是一个对象,在这种情况下 - 我正在展示并且 OP 已使用 - 无法迭代。 (粗体以便@deceze 可以理解)。
不过,您可以在 foreach
循环中使用 fetchAll()
来实现此目的。
您的代码应如下所示:
[...]
if($sqlQueryLocalityAdd->execute(array(':country_add' => $postCountryAdd)):
foreach($sqlQueryLocalityAdd->fetchAll() as $row):
echo $row['column'];
[...]
endforeach;
endif;
[...]
Difference between an array and an Object
【讨论】:
你可以foreach
对象就好了,特别是当他们implement Traversable
时,就像PDOStatement
一样。
从未见过这样做过,但这回答了他的问题,所以......我将“仅”编辑掉。 @deceze
你还在说“不能迭代”,这显然是错误的。 OP 还(神秘地)说它可以工作一次(如果我正确解释了这个问题)。
是的,OP 在哪里说过他使用了 cursor
?如果不更改他的 Prepare
语句,就无法迭代问题中的对象 OP。所以在这种情况下,我的回答是正确的。 @deceze
它不能被迭代一次以上。它可以被迭代一次。【参考方案2】:
问题是结果集只能迭代一次;然后它被耗尽,MySQL 将其丢弃,并且您无法再次对其进行迭代。
我实际上从未尝试过,但要创建一个可以迭代多次的结果集,您需要一个可滚动光标,您应该能够创建它因此:
$sqlQueryLocalityAdd = $dbh->prepare(..., [PDO::ATTR_CURSOR => PDO::CURSOR_SCROLL]);
理论上,您应该能够多次迭代结果。
如果这不起作用,请使用$sqlQueryLocalityAdd->fetchAll()
将数据提取到一个数组中,并根据需要尽可能频繁地对其进行迭代。事实上,这似乎是 MySQL 的唯一选择:https://***.com/a/19076778/476
【讨论】:
我终于明白了。 OP 令人困惑的部分只显示了一个 foreach 块。它并没有在语句生成的结果集的初始完整迭代的步骤中死亡,但它正在死亡,因为稍后的某个地方(未在帖子中显示)他正在尝试另一个 foreach 迭代。 @Ray 丁丁丁丁!我们赢了!【参考方案3】:$sqlQueryLocalityAdd
不是结果集,它是 PDOStatement
对象,您只能直接对其进行一次迭代(正如 deceze 明确指出的那样)。
execute()
语句在查询成功时返回 boolean
true 或 false。
如果运行成功,您需要在查询后从中获取结果并迭代返回的数组:
$success = $sqlQueryLocalityAdd->execute(array(':country_add' => $postCountryAdd));
if($success)
$results = $sqlQueryLocalityAdd->fetchAll();
foreach($results as $localityAddRow)
echo '<option value="';
....
生成的数组 $results
只是一个普通数组,因此您可以根据需要对其进行多次迭代。
注意:如果 execute()
返回 false,则查询有问题 - 成功运行的查询返回空结果集结果仍将导致 true
。
【讨论】:
PDOStatement
implements Traversable
,所以你可以直接迭代它!
@deceze 确实如此,好点。似乎无法找到有关它如何实现它的确切文档,因此不确定会发生什么。它在幕后做 fetchAll 吗?迭代结果是有道理的。
@deceze 如果那是真的,并且当传递给 foreach 时返回与 $row = $stmt->fetch()
完全相同的东西,示例代码将与 foreach 中的任何一个运行相同。你知道如果你从迭代中得到一个对象而不是一个数组吗?我
@deceze 我从来没有见过在结果集上使用直接迭代的例子,所以我想了解一下如何这样做,因为它看起来更优雅
@deceze 啊,我在另一个答案中看到了 cmets 的另一个线程。我现在明白了。顺便说一句,我的回答从未说过你不能遍历 PDOStatement。以上是关于使用多个 foreach 循环时多次使用 PDO 语句的主要内容,如果未能解决你的问题,请参考以下文章
PDO::bindParam 在 foreach 循环中,所有值都设置为相同吗?