SELECT、SELECT COUNT 和交叉引用表是否可以仅通过一个查询来处理?

Can SELECT, SELECT COUNT and cross reference tables be handled by just one query?

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

  1. 标题
  2. 副标题
  3. 描述
  4. 部件号(x 中的 1 个)
  5. 与该项目关联的照片总数
  6. 来自项目
  7. 的随机select照片
  8. 标签列表

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

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

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

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

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

数据库结构如下。

项目table:

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

照片 table:

+----------+------------+--------+
| 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   |
+----------+------------+--------+

标签table:

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

Tag/Project cross-reference table:

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

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

非常感谢大家。

您可以在 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

现在,对于标签列表,由于它 return 不止一行,您不能进行子查询,您应该为每个项目进行一次查询。好吧,事实上,如果您 return 以某种形式连接所有标签,例如逗号分隔列表: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

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

在同一查询中添加 SQL_CALC_FOUND_ROWS 而不是 SELECT COUNT 来解决第 5 项。

对于第 6 项,您可以使用 subquery 或者 LEFT JOIN 限制为一个结果。

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