MySQL子查询、视图和过程;哪个(如果有的话)是正确的?

MySQL子查询、视图和过程;哪个(如果有的话)是正确的?,mysql,sql,views,Mysql,Sql,Views,我编写了一个查询,其中包含一组子查询: SELECT `board_id`, `post_count`, ROUND(`post_age_avg`, 3) as `post_age_avg`, ROUND(`post_rating_avg`, 3) as `post_rating_avg`, ROUND(`board_age`, 3) as `board_age`, ROUND(1 - (`post_age_avg` / `board_age`),

我编写了一个查询,其中包含一组子查询:

SELECT
    `board_id`,
    `post_count`,
    ROUND(`post_age_avg`, 3) as `post_age_avg`,
    ROUND(`post_rating_avg`, 3) as `post_rating_avg`,
    ROUND(`board_age`, 3) as `board_age`,
    ROUND(1 - (`post_age_avg` / `board_age`), 3) AS `board_usage`,
    ROUND((`post_count` / `board_age`) * `post_rating_avg`, 3) AS `board_rating`
FROM
    (SELECT
        `board_id`,
        (SELECT COUNT(*) FROM `post` WHERE `post`.`board_id` = `board`.`board_id`) AS `post_count`,
        (SELECT AVG(TIME_TO_SEC(TIMEDIFF(NOW(), `post`.`created_on`)) / 3600) FROM `post` WHERE `post`.`board_id` = `board`.`board_id`) as `post_age_avg`,
        (SELECT AVG(`rating`) FROM `post` WHERE `post`.`board_id` = `board`.`board_id`) AS `post_rating_avg`,
        TIME_TO_SEC(TIMEDIFF(NOW(), `board`.`created_on`)) / 3600 AS `board_age`
    FROM `board`) AS `board_stats`
现在,虽然我非常愿意接受关于优化或改进此查询的建议,但我的问题涉及如何存储此查询以供将来使用

视图会很好,但是根据MySQL手册页面:

  • 语句不能在
    FROM
    子句中包含子查询
因此,我将查询封装在一个过程中。工作正常,请拨打:

CALL get_board_stats();
然而,我很快发现,在将结果用作子查询方面,使用过程的灵活性有限(读零)。和其他人一样,我发现:

SELECT * FROM (CALL get_board_stats()) AS `board_stats`;
其任何排列在句法上都是无效的

所以我的问题是;我如何才能实现(如果可能的话)这样一种场景:将此查询存储起来,以便以后在后续查询中作为“虚拟表”使用,从而允许执行以下操作:

SELECT * FROM /* give_me_board_stats_somehow() */ WHERE ...

Alrighty@OMG Ponies,这是我将要使用的最终版本(现在),因为它产生了相同的结果集,具有相同的数值精度。它与您的非常相似,只是为了(再次)支持子查询,我省略了
JOIN
,尽管这次不是作为派生表中的列。有人告诉我这效率较低(例如,与
JOIN
解决方案相比),也许您可以解释一下:

SELECT
    `board`.`board_id`,
    (SELECT COUNT(*) FROM `post` WHERE `post`.`board_id` = `board`.`board_id`) AS `post_count`,
    ROUND((SELECT AVG(TIME_TO_SEC(TIMEDIFF(NOW(), `post`.`created_on`)) / 3600) FROM `post` WHERE `post`.`board_id` = `board`.`board_id`), 3) AS `post_age_avg`,
    ROUND((SELECT AVG(`rating`) FROM `post` WHERE `post`.`board_id` = `board`.`board_id`), 3) AS `post_rating_avg`,
    ROUND(TIME_TO_SEC(TIMEDIFF(NOW(), `board`.`created_on`)) / 3600, 3) AS `board_age`,
    ROUND(1 - ((SELECT AVG(TIME_TO_SEC(TIMEDIFF(NOW(), `post`.`created_on`)) / 3600) FROM `post` WHERE `post`.`board_id` = `board`.`board_id`) / (TIME_TO_SEC(TIMEDIFF(NOW(), `board`.`created_on`)) / 3600)), 3) AS `board_usage`,
    ROUND(((SELECT COUNT(*) FROM `post` WHERE `post`.`board_id` = `board`.`board_id`) / (TIME_TO_SEC(TIMEDIFF(NOW(), `board`.`created_on`)) / 3600)) * (SELECT AVG(`rating`) FROM `post` WHERE `post`.`board_id` = `board`.`board_id`), 3) AS `board_rating`
FROM `board`
(我想发布一些比这个wad格式更好的东西,但是Workbench beautify在更大的查询中很糟糕,我没有这个努力:p)


出于某种原因,您的解决方案继续为
线路板使用情况
线路板评级
提供不正确的结果。您不需要派生表-使用:

CREATE VIEW your_view AS
   SELECT b.board_id
          COUNT(p.post_id) AS post_count,
          ROUND(AVG(TIME_TO_SEC(TIMEDIFF(NOW(), p.created_on)) / 3600), 3) AS post_age_avg,
          ROUND(AVG(p.rating), 3) AS post_rating_avg,
          ROUND(TIME_TO_SEC(TIMEDIFF(NOW(), b.created_on)) / 3600, 3) AS board_age,
          ROUND(1 - (AVG(TIME_TO_SEC(TIMEDIFF(NOW(), p.created_on)) / 3600) / TIME_TO_SEC(TIMEDIFF(NOW(), b.created_on)) / 3600), 3) AS board_usage,
          ROUND(COUNT(p.*) / (TIME_TO_SEC(TIMEDIFF(NOW(), b.created_on)) / 3600), 3) AS board_rating
     FROM BOARD b
LEFT JOIN POST p ON p.board_id = b.board_id
 GROUP BY b.board_id

…尽管使用
舍入
我不建议在您需要值的任何计算之后使用。

您不需要派生表-使用:

CREATE VIEW your_view AS
   SELECT b.board_id
          COUNT(p.post_id) AS post_count,
          ROUND(AVG(TIME_TO_SEC(TIMEDIFF(NOW(), p.created_on)) / 3600), 3) AS post_age_avg,
          ROUND(AVG(p.rating), 3) AS post_rating_avg,
          ROUND(TIME_TO_SEC(TIMEDIFF(NOW(), b.created_on)) / 3600, 3) AS board_age,
          ROUND(1 - (AVG(TIME_TO_SEC(TIMEDIFF(NOW(), p.created_on)) / 3600) / TIME_TO_SEC(TIMEDIFF(NOW(), b.created_on)) / 3600), 3) AS board_usage,
          ROUND(COUNT(p.*) / (TIME_TO_SEC(TIMEDIFF(NOW(), b.created_on)) / 3600), 3) AS board_rating
     FROM BOARD b
LEFT JOIN POST p ON p.board_id = b.board_id
 GROUP BY b.board_id

…尽管使用
ROUND
我不建议在您需要值的任何计算之后使用。

谢谢@OMG Ponies-这似乎可以解决问题!但有一个问题,我不得不将
COUNT(p.*)
替换为
COUNT(p.post\u id)
(或任何列),因为这会导致语法错误。是否存在别名为
p.*
的语法可接受的情况?@Bracketworks:Corrected。如果您查看文档,
p.*
etc语法是可以接受的。好的,谢谢@OMG Ponies-我只提到了别名,因为它发出了一个错误。不过,我现在注意到,我最初查询的结果集与您发布的解决方案之间存在一些严重的不一致。我只是在整理它,看看我们中是否有人在什么地方弄坏了东西。@Bracketworks:很高兴看到您正在测试--我唯一能看到问题的列是
板。在结果集中的
相关列上创建了,因为我没有将该列包含在
GROUP BY
--在MySQL中有效,但每个
板id将只返回一行。我没有你的数据可以测试:(我更新了我的问题,当你可以的时候看看;也许可以分享一下想法。谢谢@OMG Ponies-这似乎很管用!但是有一个问题,我不得不用
COUNT(p.*)
替换
COUNT(p.post\u id)
(或者其他任何列)因为它导致了语法错误。在某些情况下,别名
p.*
是可接受的语法吗?@Bracketworks:Corrected.
p.*
etc语法是可接受的,如果您查看文档的话。好的,谢谢@OMG Ponies-我只提到了别名,因为它发出了一个错误。不过,我现在已经注意到了我的原始查询的结果集与您发布的解决方案之间存在一些严重的不一致。我只是对其进行排序,看看我们中是否有人在某个地方弄错了什么。@Bracketworks:很高兴看到您正在测试--我能看到问题的唯一一列是结果集中与
相关的列上创建的
BOARD未将列包含在
分组依据中
——在MySQL中有效,但每个
板id将只返回一行。
我没有您的数据可以测试:(我更新了我的问题,如果可以,请看一看;也许可以分享一下您的想法。