我编写了一个查询,其中包含一组子查询:
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`
现在,虽然我对优化或改进此查询的建议持开放态度,但我的问题是以何种方式存储此查询以供将来使用。
视图会很棒,但是根据CREATE VIEW
上的MySQL手册页:
SELECT
语句不能在FROM
子句中包含子查询。
所以我在程序中封装了查询。工作正常,致电:
CALL get_board_stats();
然而,我很快发现,使用过程作为子查询时,使用过程的灵活性有限(读零)。像其他有类似问题的SO一样,我发现:
SELECT * FROM (CALL get_board_stats()) AS `board_stats`;
其中的任何排列在语法上都是无效的。
所以我的问题是;我怎样才能实现(,如果可能的话)一个场景,在这个场景中可以存储这个查询,以便以后在后续查询中用作“虚拟表”,允许人们做类似的事情:
SELECT * FROM /* give_me_board_stats_somehow() */ WHERE ...
Alrighty @OMG Ponies,这是我要使用的最终版本( for now ),因为它生成相同的结果集,具有相同的数值精度。它与你的非常相似,除了我省略了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`
(我发布的格式比这个格式更好,但Workbench美化很糟糕,查询较多,我没有努力:P )
出于某种原因,您的解决方案继续为board_usage
和board_rating
提供不正确的结果。
答案 0 :(得分:1)
您不需要派生表 - 使用:
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
我不推荐,直到经过任何计算后你都需要这些值。