我有一个显示项目列表的页面。每个项目都显示从mysqli数据库检索到的以下数据:
- 标题
- 副标题
- 说明
- 零件号(第1个,共x个)
- 与该项目关联的照片总数
- 从项目中随机选择的照片
- 标签列表
使用分页系统每页显示6个项目
由于这是基于我的一个旧项目,它最初是用草率的代码完成的(我只是在学习,不知道更多),使用了许多查询。事实上,只有第5-7项有三个,这些都包含在使用分页系统的while循环中。我现在很清楚,这甚至不是做生意的正确方式。
我熟悉INNER JOIN和子查询的使用,但我担心仅使用一个选择查询可能无法获得所有这些数据,原因如下:
-
使用基本的
SELECT
查询,项目1-4就足够简单了,但是。。。 -
项目5需要
SELECT COUNT
AND。。。 -
项6需要具有
ORDER by RAND LIMIT 1
的基本SELECT
查询从与每个项目相关的所有照片中随机选择一张(使用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手册,所以如果有什么方法可以解决这个问题,那就太棒了。
非常感谢大家。
您可以在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
正如您在第1项到第4项中所说,您已经有了解决方案。
将SQL_CALC_FOUND_ROWS
而不是SELECT COUNT
添加到同一查询中以解决项目5。
对于第6项,您可以使用子查询,也可以使用限制为一个结果的LEFT JOIN
。
对于最新的项目,您还可以使用子查询将所有标记连接到一个结果中(例如,用逗号分隔)。