【问题标题】:Get all rows inside a foreach loop and echo an array result?获取 foreach 循环中的所有行并回显数组结果?
【发布时间】:2020-08-11 09:14:33
【问题描述】:

我试图在 foreach 循环中获取所有行,但它没有按应有的方式工作。

<?php 
foreach ($locations_loop as $row):

    $lr_id  = $row["id"];
    $stmtlr = $pdo->prepare("SELECT * FROM locations_rating WHERE l_id = {$lr_id}");
    $stmtlr->execute();
    $stlr_loop = $stmtlr->fetchAll(PDO::FETCH_ASSOC);
    if (empty($stlr_loop)) {
        $loc_rate[] = "0";
    } else {
        foreach($stlr_loop as $rowlr):
            $loc_rate[] = $rowlr["stars"];
        endforeach;
    }
    
    $rating_array = array_values($loc_rate);
    $rating_avg   = array_sum($rating_array) / count($rating_array);
?>      
<?=round($rating_avg, 1);?>    
<?php endforeach; ?>

$rating_avg 每次脚本运行时都会输出其他内容。它在 foreach 循环之外工作正常。我试图加入这两个表,但没有运气,因为它只输出一行。

【问题讨论】:

  • 1.不要在循环内准备 sql 语句。 整个想法是您准备一次,绑定一次,然后在循环中执行。 2. 使用带有绑定参数的占位符。 3. 如果您计划在代码的同一“层”中循环遍历结果集,请不要使用fetchAll()。 4. 不要在已经被索引的数组上调用array_values()——它绝对不会改变。
  • @mickmackusa 为什么不准备内部循环。非常感谢您解释这样做的缺点
  • 因为做一次事情比一次又一次做同样的事情容易得多。不是很明显吗?
  • 5.经过仔细检查,我不明白为什么您需要多次访问数据库。将 WHERE l_id IN (...) 与您的 array_column($locations_loop, 'id') 数组一起使用。 6.求和和计数是sql完全可以做的事情。将所有处理和逻辑移动到 sql 中。 7. 仅从 db 表中获取您打算使用的数据——将* 替换为stars
  • 我得到你,但不是同时 :D 如果不是太多要求,你能按照你解释的方式修改我在上面发布的代码吗?

标签: php mysql arrays


【解决方案1】:

我可能想得太远了,但这只是我想到的一种技术,它可以确保所有位置 ID 在结果集中获得平均值。

假设$locations_loop(包含数组类型数据的变量的名字不好,tbh)具有以下数据:

$locations_loop = [
    ['id' => 1],
    ['id' => 2],
    ['id' => 3],
    ['id' => 4],
];

您有一个具有以下架构的数据库表:(db-fiddle demo)

CREATE TABLE `locations_rating` (
  `id` int(11) NOT NULL,
  `l_id` int(11) NOT NULL,
  `stars` int(11) NOT NULL DEFAULT 0
) ENGINE=InnoDB DEFAULT CHARSET=latin1;

INSERT INTO `locations_rating` (`id`, `l_id`, `stars`) VALUES
(1, 3, 4),
(2, 2, 2),
(3, 1, 0),
(4, 2, 5),
(5, 3, 2),
(6, 1, 10);

然后,您可以通过从id 值的列创建“派生表”,然后将数据库数据连接到它们,从而在一次访问数据库中获取所有数据。像这样的:

SELECT def.l_id,
       ROUND(AVG(COALESCE(stars, 0)), 1) avg
FROM (
  (SELECT 1 AS l_id)
  UNION (SELECT 2)
  UNION (SELECT 3)
  UNION (SELECT 4)
 ) AS def
LEFT JOIN locations_rating AS loc ON def.l_id = loc.l_id
GROUP BY def.l_id

使用准备好的语句和绑定参数来做到这一点:

$locationIds = array_column($locations_loop, 'id');
$countIds = count($locationIds);

$fabricatedRows = implode(' UNION ', array_fill(0, $countIds, '(SELECT ? AS l_id)'));

$sql = "SELECT derived.l_id,
               ROUND(AVG(COALESCE(stars, 0)), 1) avg
        ($fabricatedRows) AS derived
        LEFT JOIN locations_rating as loc ON derived.l_id = loc.l_id
        GROUP BY def.l_id";
$stmt = $pdo->prepare($sql);
$stmt->execute($locationIds);
var_export($stmt->fetchAll(PDO::FETCH_ASSOC));

应该输出:(我在本地环境中测试了这种技术是成功的)

[
    ['l_id' => 1, 'avg' => 5.0],
    ['l_id' => 2, 'avg' => 3.5],
    ['l_id' => 3, 'avg' => 3.0],
    ['l_id' => 4, 'avg' => 0.0],
]

【讨论】:

    猜你喜欢
    • 2018-06-27
    • 2016-11-23
    • 2015-09-18
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-03-10
    • 1970-01-01
    相关资源
    最近更新 更多