使用多个 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-&gt;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-&gt;fetch() 完全相同的东西,示例代码将与 foreach 中的任何一个运行相同。你知道如果你从迭代中得到一个对象而不是一个数组吗?我 @deceze 我从来没有见过在结果集上使用直接迭代的例子,所以我想了解一下如何这样做,因为它看起来更优雅 @deceze 啊,我在另一个答案中看到了 cmets 的另一个线程。我现在明白了。顺便说一句,我的回答从未说过你不能遍历 PDOStatement。

以上是关于使用多个 foreach 循环时多次使用 PDO 语句的主要内容,如果未能解决你的问题,请参考以下文章

PDO::bindParam 在 foreach 循环中,所有值都设置为相同吗?

带有 PDO::FETCH_ASSOC 的 foreach 循环,提供的参数无效

多个 foreach 循环语句

如何在foreach循环中显示来自PDO的数据

PDO 准备状态与手动查询的结果不同

PDO 查询未在 PHP foreach 循环中返回结果