只能通过一个查询处理SELECT,SELECT COUNT和交叉引用表吗?

时间:2017-01-14 02:22:31

标签: php mysqli subquery inner-join nested-query

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

  1. 标题
  2. 字幕
  3. 描述
  4. 部件号(x中的1个)
  5. 与该项目相关的照片总数
  6. 项目中随机选择的照片
  7. 标签列表
  8. 使用分页系统每页显示6个项目

    由于这是基于我的一个旧项目,它最初使用草率代码(我只是学习,并且不知道更好)使用许多查询。实际上,只有第5-7项,这些包含在与分页系统一起工作的while循环中。我现在非常清楚,这甚至不是开展业务的正确方式。

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

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

    • 第5项需要SELECT COUNT AND ...

    • 第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手册,所以如果有任何方法可以解决这个问题,那就太棒了。

    非常感谢你们。

2 个答案:

答案 0 :(得分: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

答案 1 :(得分:1)

正如您在第1至4项中所说,您已经有了解决方案。

使用SQL_CALC_FOUND_ROWS而不是SELECT COUNT添加相同的查询来解决第5项。

对于第6项,您可以使用subqueryLEFT JOIN限制一个结果。

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