pau*_*o77 5 php mysql sql nested
我遇到了一种情况,我试图从与 PHP 的多对多关系输出 MySQL 数据透视表/链接表的内容。
在下面的代码中,我有一系列包含图像的板。实际的板预览是使用 PHP 的第一个块输出的,但在其中我需要一个嵌套的 while 循环来输出图像本身。
枢轴/链接表被称为boards_images有两列board_id,并且这些都是表和表image_id的外键。下面的主要代码下面给出了表格的表示。boardsimages
因为某些板的图像已经存在于其他板上,所以我显然需要某种类型的条件逻辑,以便在相关板存在时输出图像。
每个板预览只会显示四个图像,因此我需要LIMIT 4向 MySQL 添加一个子句
我的问题
解决这个问题的最佳方法是什么,我:
a) 需要执行两次数据库调用,一次在父 while 循环中,一次在嵌套 while 循环中,或者我是否需要使用多个 JOIN 从父 while 循环中的 MySQL 数据库获取所有信息?
b) 如何实际输出数据透视表/链接表的内容?我似乎不知道如何做到这一点。
<?php
// $db_id is a variable created from a user login $_SESSION value
$sql = "SELECT boards.board_id, boards.board_name, users.user_id
FROM boards
JOIN users ON boards.user_id = users.user_id
WHERE users.user_id = :user_id
ORDER BY boards.board_id DESC";
$stmt = $connection->prepare($sql);
$stmt -> execute([
':user_id' => $db_id
]);
// parent while loop that outputs the board name
while ($row = $stmt->fetch()) {
$dbBoardname = htmlspecialchars($row['board_name']);
?>
<div class="board-component">
<h2><?= $dbBoardname; ?></a></h2>
<?php
// --- NESTED INNER WHILE LOOP
$SQL2 = "SELECT boards_images.board_id, boards_images.image_id, images.filename
FROM boards_images
JOIN images ON boards_images.image_id = images.image_id
WHERE boards_images.board_id = :board_id
LIMIT 4";
$stmt2 = $connection->prepare($SQL2);
$stmt2 -> execute([
':board_id' => $dbBoardId
]);
while ($row2 = $stmt2->fetch()) {
$dbImageId = htmlspecialchars($row['image_id']);
$dbImageFilename = htmlspecialchars($row['filename']);
?>
<img src='<?= $wwwRoot . "/images-lib/{$dbImageFilename}" ?>' >
<?php } ?> <!-- end of nested while loop -->
</div>
<?php } ?> <!-- end of parent while loop -->
Run Code Online (Sandbox Code Playgroud)
表格的表示
// 'fk' stands for foreign key
// BOARDS_IMAGES LINKING / PIVOT TABLE
+----------------+----------------+
| board_id (fk) | image_id (fk) |
+----------------+----------------+
| 1 | 23 |
| 1 | 106 |
| 1 | 55 |
| 1 | 22 |
+----------------+----------------+
// BOARDS TABLE
+-------------+--------------+---------------+
| board_id | board_name | user_id (fk) |
----------------------------------------------
| 1 | London | 21 |
| 2 | France | 21 |
+-------------+--------------+---------------+
// IMAGES TABLE
+-------------+--------------------+---------------+
| image_id | filename | user_id (fk) |
---------------------------------------------------+
| 23 | BigBen.jpeg | 21 |
| 106 | TowerBridge.jpeg | 21 |
| 55 | TheMall.jpg | 21 |
| 22 | BuckPalace.jpg | 21 |
+-------------+--------------------+---------------+
// USERS TABLE
+-----------------+----------------+
| user_id | username |
+-----------------+----------------+
| 21 | johndoe |
+-----------------+----------------+
Run Code Online (Sandbox Code Playgroud)
a) 需要执行两次数据库调用,一次在父 while 循环中,一次在嵌套 while 循环中,或者我是否需要使用多个 JOIN 从父 while 循环中的 MySQL 数据库获取所有信息?
您可以执行一个查询来获取所有必要的数据,我们可以限制 php 中显示的图像数量,并且不需要连接到 users 表,因为在boards 表中有 FK:
SELECT boards.board_name, images.filename
FROM boards
INNER JOIN boards_images on boards_images.board_id = boards.board_id
INNER JOIN images on boards_images.image_id = images.image_id
WHERE boards.user_id = :user_id
Run Code Online (Sandbox Code Playgroud)
b) 如何实际输出数据透视表/链接表的内容?我似乎不知道如何做到这一点。
上述查询的输出结果如下:
board_name | filename
-------------------------------
London | BigBen.jpeg
London | TowerBridge.jpeg
London | TheMall.jpg
London | BuckPalace.jpg
France | BigBen.jpeg
France | TowerBridge.jpeg
France | TheMall.jpg
France | BuckPalace.jpg
Run Code Online (Sandbox Code Playgroud)
你的 php 循环可能看起来像这样:
<?php
// $db_id is a variable created from a user login $_SESSION value
$sql = "SELECT boards.board_name, images.filename
FROM boards
INNER JOIN boards_images on boards_images.board_id = boards.board_id
INNER JOIN images on boards_images.image_id = images.image_id
WHERE boards.user_id = :user_id";
$stmt = $connection->prepare($sql);
$stmt -> execute([
':user_id' => $db_id
]);
$dbBoardname_last = '';
$imgcount = 0;
while ($row = $stmt->fetch()) {
$dbBoardname = htmlspecialchars($row['board_name']);
$dbImageFile = "$wwwRoot/images-lib/" . htmlspecialchars($row['filename']);
//if the boardname is the same as the previous row only add images.
if($dbBoardname != $dbBoardname_last)
{
//reset the image count for new boards
$imgcount = 0;
echo "<div class=\"board-component\"><h2>$dbBoardname</a></h2>";
}
//By counting the images within the loop we can avoid using multiple or nested queries to the DB
if($imgcount < 4) {
echo "<img src=\"$dbImageFile\">";
}
$imgcount++;
if($dbBoardname != $dbBoardname_last)
{
echo '</div>';
}
//record the last board_name to check if a new board element should be created
$dbBoardname_last = $dbBoardname;
}
?>
Run Code Online (Sandbox Code Playgroud)
注意:希望这段代码能按您的预期工作,但从长远来看,我认为最佳实践是将 SQL 输出解析为 JSON 对象并对其进行迭代,代码可能会更干净