【问题标题】:PHP While and ForEach not producing desired resultsPHP While 和 ForEach 没有产生预期的结果
【发布时间】:2017-10-06 22:11:05
【问题描述】:

我目前正在使用while 语句来获取meal_id 的每个关联记录,但我的foreach 没有按预期工作。我的目标是为找到的每餐生成餐食行,然后在其下方显示与该餐食相关的餐食项目,然后循环到下一餐并重复。

目前,结果是显示正确的一餐,但随后显示其下每餐的每餐项目。如:

Meal
Meal Item
Meal Item
Unrelated Meal Item
Unrelated Meal Item
Unrelated Meal Item
Unrelated Meal Item
Unrelated Meal Item
Unrelated Meal Item
Unrelated Meal Item

什么时候该做:

Meal 1
Meal Item
Meal Item

Meal 2
Meal Item

Meal 3
Meal Item
Meal Item
Meal Item
Meal Item

我还想获得那顿饭的项目数,并将其显示在表的餐行中。 到目前为止,这是我的代码,您可以提供的任何帮助都会很棒! :-)

<?php
$con=mysqli_connect($DBServer,$DBUser,$DBPass,$DBName);
// Check connection
if (mysqli_connect_errno())
{
echo "Failed to connect to MySQL: " . mysqli_connect_error();
}
    $view = 'empty';
if(isset($_GET["v"]))
    $view = $_GET["v"];

switch($view)
{
    default:
        $result = mysqli_query($con,"SELECT * FROM tblmeals INNER JOIN tblmealitems ON tblmeals.meal_id = tblmealitems.meal_id WHERE DATE(meal_date) = CURDATE() ORDER BY meal_date DESC, meal_time DESC");
        $viewstatus = "Today (default view)";
        break;
    case 'all':
        $result = mysqli_query($con,"SELECT * FROM tblmeals INNER JOIN tblmealitems ON tblmeals.meal_id = tblmealitems.meal_id ORDER BY meal_date DESC, meal_time DESC");
        $viewstatus = "All Records";
        break;
    case 'today':
        $result = mysqli_query($con,"SELECT * FROM tblmeals INNER JOIN tblmealitems ON tblmeals.meal_id = tblmealitems.meal_id WHERE DATE(meal_date) = CURDATE() ORDER BY meal_date DESC, meal_time DESC");
        $viewstatus = "Today";
        break;
    case 'yesterday':
        $result = mysqli_query($con,"SELECT * FROM tblmeals INNER JOIN tblmealitems ON tblmeals.meal_id = tblmealitems.meal_id WHERE DATE(meal_date) = CURDATE() - INTERVAL 1 DAY ORDER BY meal_date DESC, meal_time DESC");
        $viewstatus = "Yesterday";
        break;
    case 'week':
        $result = mysqli_query($con,"SELECT * FROM tblmeals INNER JOIN tblmealitems ON tblmeals.meal_id = tblmealitems.meal_id WHERE meal_date BETWEEN CURDATE() - INTERVAL 7 DAY AND CURDATE() ORDER BY meal_date DESC, meal_time DESC");
        $viewstatus = "Last 7 Days";
        break;
    case "fortnight":
        $result = mysqli_query($con,"SELECT * FROM tblmeals INNER JOIN tblmealitems ON tblmeals.meal_id = tblmealitems.meal_id WHERE meal_date BETWEEN CURDATE() - INTERVAL 14 DAY AND CURDATE() ORDER BY meal_date DESC, meal_time DESC");
        $viewstatus = "Last 14 Days";
        break;
} ?><br>

<div class="viewdesc">Current View: <strong><?php echo($viewstatus); ?></strong></div><br>
<br>
<?php 

    // Start record fail error checking

    if (!$result) {
    printf("Error: %s\n", mysqli_error($con));
    exit();
}
    // Start record fail error checking */

    if (mysqli_num_rows($result) === 0) {?>
          <div id="resultserror">
No results could found for the selected view.</div>
          <?php } else { ?>
              <table id="results" width="100%" cellpadding="3" cellspacing="0">
<tr>
<th align="center">Meal #</th>
<th align="center">User #</th>
<th align="center">Meal Items</th>
<th align="center">Meal Date</th>
<th align="center">Meal Time</th>
<th align="center">Meal Notes</th>
</tr>
<?php
    while($row = mysqli_fetch_assoc($result))
{
    ?>
<tr>

<td align='center'><?php echo($row['meal_id']);?></td>
<td align='center'><?php echo($row['user_id']);?></td>
<td align='center'><?php echo("Items: " . mysqli_num_rows($result) . "");?></td>
<td align='center'><?php echo(date("d/m/Y", strtotime($row['meal_date'])));?></td>
<td align='center'><?php echo(date("g:i A", strtotime($row['meal_time'])));?></td>
<td align='center'><?php echo($row['meal_notes']);?></td>

</tr>
<?php foreach ($result as $row)
{?>
<tr>
<td align='center' colspan='4'><?php echo($row['meal_item_name']);?></td>
<td align='center'><?php echo($row['meal_item_measure']);?></td>
<td align='center'><?php echo($row['meal_item_measurement']);?></td>
</tr>
<?php
}
}
?>
<tfoot>
<tr>
  <td colspan="8" align="center">- end of report -</td></tr></tfoot>
</table>
<?php
mysqli_close($con);
                     }?>

【问题讨论】:

  • 我建议不要使用JOIN,而是在循环内执行第二组查询(每餐一个,具体获取该餐项)。使用 JOIN 执行此操作会导致您为每顿包含该餐的每餐获得 [该餐中的项目数] 行。在您的案例中循环时,您需要重组/处理它,而在使用额外查询路由时您不必这样做。
  • 尽管有成千上万的用户使用数百种餐点,每个用户都有自己的数千种餐点,但这在性能方面如何公平?来回查询不同的表会不会归结为过度处理?
  • 取决于您的索引,现代 DBMS 可以毫不费力地处理它。
  • 好的,试一试!谢谢:-)

标签: php mysqli foreach while-loop


【解决方案1】:

稍微重构您的代码以使用 2 个查询而不是 JOIN

请注意,我不喜欢这样交织 HTML 和 PHP 标记 - 但这可能是个人喜好,而不是本问题的主题:

<?php
$con=mysqli_connect($DBServer,$DBUser,$DBPass,$DBName);
// Check connection
if (mysqli_connect_errno())
{
    echo "Failed to connect to MySQL: " . mysqli_connect_error();
}

$view = 'empty';
if(isset($_GET["v"]))
    $view = $_GET["v"];

switch($view)
{
    case 'all':
        $result = mysqli_query($con,"SELECT * FROM tblmeals ORDER BY meal_date DESC, meal_time DESC");
        $viewstatus = "All Records";
        break;
    case 'today':
        $result = mysqli_query($con,"SELECT * FROM tblmeals WHERE DATE(meal_date) = CURDATE() ORDER BY meal_date DESC, meal_time DESC");
        $viewstatus = "Today";
        break;
    case 'yesterday':
        $result = mysqli_query($con,"SELECT * FROM tblmeals WHERE DATE(meal_date) = CURDATE() - INTERVAL 1 DAY ORDER BY meal_date DESC, meal_time DESC");
        $viewstatus = "Yesterday";
        break;
    case 'week':
        $result = mysqli_query($con,"SELECT * FROM tblmeals WHERE meal_date BETWEEN CURDATE() - INTERVAL 7 DAY AND CURDATE() ORDER BY meal_date DESC, meal_time DESC");
        $viewstatus = "Last 7 Days";
        break;
    case "fortnight":
        $result = mysqli_query($con,"SELECT * FROM tblmeals WHERE meal_date BETWEEN CURDATE() - INTERVAL 14 DAY AND CURDATE() ORDER BY meal_date DESC, meal_time DESC");
        $viewstatus = "Last 14 Days";
        break;
    default:
        $result = mysqli_query($con,"SELECT * FROM tblmeals WHERE DATE(meal_date) = CURDATE() ORDER BY meal_date DESC, meal_time DESC");
        $viewstatus = "Today (default view)";
        break;
}

if (!$result) {
    printf("Error: %s\n", mysqli_error($con));
    exit();
}

$meals = array();
while($row = mysqli_fetch_assoc($result))
{
    $meal = array(
        "meal_id" => $row["meal_id"],
        "user_id" => $row["user_id"],
        "items" => array(),             // Gets filled next
        "date" => date("d/m/Y", strtotime($row['meal_date'])),
        "time" => date("g:i A", strtotime($row['meal_time'])),
        "notes" => $row['meal_notes']
    );

    $itemResult = mysqli_query($con, "SELECT * FROM tblmealitems WHERE meal_id = ".$row["meal_id"]);
    while($itemRow = mysqli_fetch_assoc($itemResult))
    {
        $meal["items"][] = array(
            "meal_item_name" => $itemRow["meal_item_name"],
            "meal_item_measure" => $itemRow["meal_item_measure"],
            "meal_item_measurement" => $itemRow["meal_item_measurement"],
        );
    }

    // Add it to the meals list
    $meals[] = $meal;
}

?>
<div class="viewdesc">Current View: <strong><?php echo($viewstatus); ?></strong></div><br>
<br>
<?php 
    if (count($meals) === 0) {?>
        <div id="resultserror">
            No results could found for the selected view.
        </div>
    <?php } else { ?>
        <table id="results" width="100%" cellpadding="3" cellspacing="0">
            <tr>
                <th align="center">Meal #</th>
                <th align="center">User #</th>
                <th align="center">Meal Items</th>
                <th align="center">Meal Date</th>
                <th align="center">Meal Time</th>
                <th align="center">Meal Notes</th>
            </tr>
    <?php
        foreach($meals as $meal)
        {
    ?>
            <tr>
                <td align='center'><?php echo($meal['meal_id']);?></td>
                <td align='center'><?php echo($meal['user_id']);?></td>
                <td align='center'><?php echo("Items: " . count($meal['items']) . "");?></td>
                <td align='center'><?php echo(date("d/m/Y", strtotime($meal['meal_date'])));?></td>
                <td align='center'><?php echo(date("g:i A", strtotime($meal['meal_time'])));?></td>
                <td align='center'><?php echo($meal['meal_notes']);?></td>
            </tr>
            <?php foreach ($meal["items"] as $mealItem)
            {?>
                    <tr>
                        <td align='center' colspan='4'><?php echo($mealItem['meal_item_name']);?></td>
                        <td align='center'><?php echo($mealItem['meal_item_measure']);?></td>
                        <td align='center'><?php echo($mealItem['meal_item_measurement']);?></td>
                    </tr>
            <?php
            }
        }
    ?>
    <tfoot>
        <tr>
        <td colspan="8" align="center">- end of report -</td>
        </tr>
    </tfoot>
</table>
<?php
    mysqli_close($con);
}?>

【讨论】:

  • Hm.. 你不能(至少)建议 OP 应该在每种情况下设置 $query 字符串,并在 end 处运行 mysli_query( $query );开关?
  • 虽然我需要修改一些东西,但 @cckep 的效果非常好,例如需要将 while($row = mysqli_fetch_assoc($result)) 语句更改为 ` $meal = array( "meal_id" => $row[ "meal_id"], "user_id" => $row["user_id"], "items" => array()` and "meal_date" =&gt; $row['meal_date'], "meal_time" =&gt; $row['meal_time'], "meal_notes" =&gt; $row['meal_notes']);
  • 出于好奇,是否很难将数组的 2 部分加在一起以显示总膳食重量(通过添加每个 meal_item_measure 所以如果它是 600 克和 300 克,它将显示在餐头为 900 克(我知道会涉及到处理克、公斤、磅等变量的配方,但更多的是调用参考不仅仅是列表中项目的数量,而是数学计数的项目数组值。
  • @cale_b 我​​已经认为我比回答这个问题需要走得更远了(尽管我必须承认我实际上在移动部分 OPs 代码时考虑过这样做......虽然我没有想要更改太多,以便 OP 仍然可以识别他的代码并看到我更改的相关部分) - 如果您觉得需要,请随时编辑答案(或提供您自己的);-)
  • @cloudseeker 你可以在这些循环中做任何你想做的事情。只需创建一个整体“膳食重量”并在内部循环中添加各个项目的重量(之前将它们转换为一个通用单位)。
猜你喜欢
  • 2015-04-20
  • 2019-12-13
  • 2015-07-08
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2012-09-26
  • 2017-05-22
相关资源
最近更新 更多