首页 > 解决方案 > 使用 PHP 在 MySQL DB 中的项目列表中排序标题

问题描述

希望有人知道查询/处​​理这些标题的好方法......

例如,如果您有一个食谱,它可能看起来像这样:(带有标题和成分)


沙拉

敷料

装饰


在 MySQL 数据库中,我将把这些数据存储在一个配方表中。所以这个食谱可能看起来像这样:

+----+---------------+-----------------+--------------------+---------------------+-----------+---------+-----------+---------+-----------+---------+
| id | ingredient_1  |  ingredient_2   |   ingredient_3     | ingredient_4 etc... | heading_a | h_a_pos | heading_b | h_b_pos | heading_c | h_c_pos |
+----+---------------+-----------------+--------------------+---------------------+-----------+---------+-----------+---------+-----------+---------+
|  1 | Fresh Lettuce | Chopped carrots | Fresh Strawberries | Vinegar             | Salad     |       1 | Dressing  |       4 | Garnish   |       7 |
+----+---------------+-----------------+--------------------+---------------------+-----------+---------+-----------+---------+-----------+---------+

成分都存放在一起,标题存放在一起。(不同的食谱将需要不同的标题和与成分相关的不同位置。)这里的标题位置(h_a_pos 等)表示成分 # 以在前面列出标题。

在查询它以显示它时,如果我运行一个简单的 SQL 查询:

SELECT * FROM recipes WHERE id = 1;

那只会给我一个所有东西的清单。这是一个 SQL 小提琴:http ://sqlfiddle.com/#!9/942d8a3/1/0

使用 PHP,我可以获取结果并将其放入数组中。而且我确信有某种方法可以对它们进行排序,但我正在画一个空白......

$response = []; // blank array
$sql_retrieve = $con->prepare("SELECT * FROM recipes WHERE id = 1");
$sql_retrieve->execute();
$result = $sql_retrieve->get_result(); 
if($result->num_rows>0){
  while($row=$result->fetch_assoc()){
    $response[] = $row;
  } // end of while
} // end of num_rows

print_r($response); // display response pre-sorting

// sort array -- not working
usort($response, function($a, $b) {
  return $a['h_a_pos'] <=> $b['h_b_pos'];
});

// would need something to order it in relation to the ingredients...

echo '<br /><br />';
print_r($response); // display response post-sorting

我可以更改数据库结构,但如果可能的话,我更愿意将其保留在一个表中。(我意识到某些成分可能未标准化,但我也没有在此示例中列出数量等。)

有人对如何存储标题有任何想法吗?我基本上只需要知道它应该是一个标题(因此可以适当地格式化),文本应该是什么,以及在哪个成分编号之前显示它。(我永远不会查询标题,所以如果这可以更好地序列化存储,那可能是一个选择......)

标签: phpmysqldatabase-design

解决方案


你有什么不正常。例如,如果您决定想要一个复杂的配方,其中成分多于列,或者成分标题多于列,您就会遇到麻烦。要吸取的重要教训是,数据库不是电子表格。

这是更接近您想要的数据库结构的东西:

CREATE TABLE categories (id SERIAL, name VARCHAR(32));
CREATE TABLE ingredients (id SERIAL, category_id BIGINT UNSIGNED NOT NULL, name VARCHAR(32));
CREATE TABLE recipes (id SERIAL, name VARCHAR(32));
CREATE TABLE ingredients_recipes (recipe_id BIGINT UNSIGNED NOT NULL, ingredient_id BIGINT UNSIGNED NOT NULL);

显然,您还需要一些外键约束来强制表之间的链接,但我们将在这里跳过。用你的成分填充它:

INSERT INTO categories VALUES (1, 'Salad'), (2, 'Dressing'), (3, 'Garnish');
INSERT INTO ingredients VALUES (1, 1, 'Fresh Lettuce'), (2, 1, 'Chopped Carrots'), (3, 1, 'Strawberries'), (4, 2, 'Balsamic Vinegar'), (5, 2, 'Olive Oil'), (6, 3, 'Sliced Almonds');
INSERT INTO recipes VALUES (1, 'My Salad');
INSERT INTO ingredients_recipes VALUES (1, 1), (1, 2), (1, 3), (1, 4), (1, 5), (1, 6);

现在,可以使用简单的连接来提取完整​​的配方:

SELECT r.name AS recipe, c.name AS category, i.name AS ingredient
FROM ingredients i
LEFT JOIN categories c ON (i.category_id = c.id)
LEFT JOIN ingredients_recipes ON (ingredient_id = i.id)
LEFT JOIN recipes r ON (recipe_id = r.id)
WHERE r.id = ?
ORDER BY c.id ASC

这里有一个小提琴来说明这一点:http ://sqlfiddle.com/#!9/aecbbd/1

(请注意,“标题”的顺序必须在创建时单独定义。在这种情况下,我只是按 ID 排序。)

现在,在您的 PHP 中,您可以轻松地执行此查询并按类别对成分进行分组:

$stmt = $con->prepare($query);
$stmt->bind_param("i", $recipe_id);
$stmt->execute();
while ($row = $stmt->fetch_assoc()) {
    $name = $row["recipe"];
    $ingredient_types[$row["category"]][] = $row["ingredient"];
}

在显示过程中,只需循环遍历数组:

<h1>How to make <?= $name ?></h1>
<?php foreach($ingredient_types as $category=>$ingredients): ?>
    <h2><?= $category ?></h2>
    <ul>
    <?php foreach ($ingredients as $ingredient): ?>
        <li><?= $ingredient ?></li>
    <?php endforeach ?>
    </ul>
<?php endforeach ?>

您的问题提到了数量,这些将ingredients_recipes作为附加列存储在数据透视表中,并且可以很容易地被拉入SELECT子句。


推荐阅读