3

我有一个显示项目列表的页面。每个项目都会显示从 mysqli 数据库中检索到的以下数据:

  1. 标题
  2. 字幕
  3. 描述
  4. 部件号(x 中的 1 个)
  5. 与该项目相关的照片总数
  6. 从项目中随机选择的一张照片
  7. 标签列表

使用分页系统每页显示 6 个项目

由于这是基于我的一个旧项目,它最初是使用许多查询用草率的代码完成的(我只是在学习,不知道更好)。第三,实际上,仅针对第 5-7 项,它们包含在与分页系统一起使用的 while 循环中。我现在很清楚,这甚至不是正确的经商方式。

我熟悉 INNER JOIN 和子查询的使用,但我担心我可能无法仅使用一个选择查询来获取所有这些数据,原因如下:

  • SELECT使用基本查询,第 1-4 项很容易,但是...

  • 第 5 项需要一个SELECT COUNTAND...

  • 第 6 项需要一个基本SELECT查询,ORDER by RAND LIMIT 1从与每个项目关联的所有照片中选择一张随机照片(使用 FilesystemIterator 是不可能的,因为照片表有一个列指示 0 如果照片处于非活动状态,1 表示处于活动状态)

  • 第 7 项是从标签和项目的交叉引用表以及包含标签 ID 和名称的表中选择的

鉴于此,我不确定是否所有这些都可以(甚至应该)通过一个查询来完成,或者是否需要多个查询。我反复阅读过,在一个while循环中嵌套一个或多个查询是多么值得用报纸拍打鼻子。我什至读过多个查询通常是个坏主意。

所以我被困住了。我意识到这听起来可能太笼统了,但我没有任何有效的代码,只有使用 4 个查询来完成这项工作的旧代码,其中 3 个嵌套在 while 循环中。

数据库结构如下。

项目表:

+-------------+---------+----------+---------------+------+
| project_id  | title   | subtitle | description   | part |
|---------------------------------------------------------|
|       1     |   Chevy | Engine   | Modify        |  1   |
|       2     |   Ford  | Trans    | Rebuild       |  1   |
|       3     |   Mopar | Diff     | Swap          |  1   |
+-------------+---------+----------+---------------+------+

照片表:

+----------+------------+--------+
| photo_id | project_id | active |
|--------------------------------|
|     1    |     1      |    1   |
|     2    |     1      |    1   | 
|     3    |     1      |    1   |
|     4    |     2      |    1   |
|     5    |     2      |    1   |
|     6    |     2      |    1   |
|     7    |     3      |    1   |
|     8    |     3      |    1   |
|     9    |     3      |    1   |
+----------+------------+--------+

标签表:

+--------+------------------+
| tag_id |        tag       |
|---------------------------|
|    1   | classic          |
|    2   | new car          |
|    3   | truck            |
|    4   | performance      |
|    5   | easy             |
|    6   | difficult        |
|    7   | hard             |
|    8   | oem              |
|    9   | aftermarket      |
+--------+------------------+

标签/项目交叉引用表:

+------------+-----------+
| project_id | tag_id    |
|------------------------|
|      1     |     1     |
|      1     |     3     |
|      1     |     4     |
|      2     |     2     |
|      2     |     5     |
|      3     |     6     |
|      3     |     9     |
+------------+-----------+

我不是要求为我编写代码,但如果我的要求是有道理的,我真诚地感谢朝着正确的方向推进。很多时候,我都在在线阅读 PHP 和 MySQLi 手册,所以如果有任何方法可以解决这个问题,那就太棒了。

非常感谢大家。

4

2 回答 2

3

您可以在SELECT子句中执行子查询,如下所示:

SELECT 
    p.title, p.subtitle, p.description, p.part,
    (SELECT COUNT(photo_id) FROM Photos where project_id = p.project_id) as total_photos, 
    (SELECT photo_id FROM Photos where project_id = p.project_id ORDER BY RAND LIMIT 1) as random_photo
FROM projects as p

现在,对于标签列表,由于它返回多于一行,因此您不能执行子查询,您应该为每个项目执行一次查询。好吧,实际上,如果您以某种连接形式返回所有标签,例如逗号分隔的列表:tag1,tag2,tag3... . 仅当您有许多项目并且检索每个单独项目的标签列表的性能相当低时才这样做。如果你真的想要,你可以:

SELECT 
    p.title, p.subtitle, p.description, p.part,
    (SELECT COUNT(photo_id) FROM Photos where project_id = p.project_id) as total_photos, 
    (SELECT photo_id FROM Photos where project_id = p.project_id ORDER BY RAND LIMIT 1) as random_photo,
    (SELECT GROUP_CONCAT(tag SEPARATOR ', ') FROM tags WHERE tag_id in (SELECT tag_id FROM tagproject WHERE project_id = p.project_id)) as tags
FROM projects as p
于 2017-01-14T02:45:31.290 回答
1

正如您从第 1 项到第 4 项所说,您已经有了解决方案。

在同一个查询中添加 aSQL_CALC_FOUND_ROWS而不是 aSELECT COUNT以解决第 5 项。

对于第 6 项,您可以使用子查询LEFT JOIN限制为一个结果。

对于最新项目,您还可以使用子查询将所有标签连接到一个结果中(例如,用逗号分隔)。

于 2017-01-14T02:45:58.227 回答