【问题标题】:"Last Post By" for forum, Join, Join and loads of Join论坛、加入、加入和大量加入的“最后发帖人”
【发布时间】:2012-07-23 06:55:26
【问题描述】:

Codeigniter; Active Records Class

从那个话题,我问了一个关于 CodeIgniter 的问题,我想现在完全原始地做它。

这是我当前的查询。

 SELECT `forums`.*, 
        Count(topics.id) threads, 
        Count(replies.id) replies, 
        `users`.`url` user_url, 
        `users`.`name` user_name,
        `ranks`.`name` user_rank  
 FROM (`forums`)  
 LEFT JOIN `topics` ON `topics`.`f_id` = `forums`.`id`  
 LEFT JOIN `replies` ON `replies`.`t_id` = `topics`.`id`  
 LEFT JOIN `users` ON `users`.`id` = `topics`.`a_id`  
 LEFT JOIN `ranks` ON `users`.`status` = `ranks`.`id`  
 LEFT JOIN (  
 SELECT `topics`.`url` topic_url, `topics`.`name` topic_name  
 FROM `topics`  
 ORDER BY `created` DESC  
 LIMIT 1  
 ) last_post ON `topics`.`f_id` = `forums`.`id`  
 GROUP BY `forums`.`id`

所以我要做的就是把所有东西都放在一个漂亮的行中。 “最后发帖者”旁边的所有内容都正常工作,如果我删除后来添加的LEFT JOIN,我会得到第一个,而不是最后一个帖子。

所以我的问题是;我现在做错了什么?

另外,一个额外的问题,我之前和一个朋友谈过,他在 PHP 和 MySQL 方面比我更了解,他告诉我把它全部存储在数据库中,last_post 以及计数线程和回复。

提前致谢。

更新

这是论坛表格

CREATE TABLE IF NOT EXISTS `forums` (  
  `id`    int(11) NOT NULL AUTO_INCREMENT,  
  `c_id`  int(11) NOT NULL,  
  `url`   varchar(255) NOT NULL,  
  `name`  varchar(255) NOT NULL,  
  `desc`  text NOT NULL,  
PRIMARY KEY (`id`),  
KEY `url` (`url`,`name`)  
) ENGINE=InnoDB DEFAULT CHARSET=utf8 AUTO_INCREMENT=9 ;  

这是主题表

CREATE TABLE IF NOT EXISTS `topics` (  
  `id` int(11) NOT NULL AUTO_INCREMENT,  
  `f_id`    int(11) NOT NULL,  
  `url`     varchar(255) NOT NULL,  
  `name`    varchar(255) NOT NULL,  
  `desc`    varchar(255) NOT NULL,  
  `body`    text NOT NULL,  
  `a_id`    int(11) NOT NULL,  
  `created` int(11) NOT NULL,  
  `edited`  int(11) NOT NULL,  
PRIMARY KEY (`id`),  
KEY `head` (`name`)  
) ENGINE=InnoDB DEFAULT CHARSET=utf8 AUTO_INCREMENT=10 ;

我也尝试过用markdown编辑来更新它的显示方式,就像我第一次做的那样,我希望这更有吸引力。

【问题讨论】:

  • 我鼓励您查看 Markdown 帮助以了解未来的问题、答案甚至 cmets。遵循此建议将对您在 StackOverflow 上的体验产生积极影响。谢谢。
  • 最后一个 JOIN 中的 LIMIT 1 导致了您的问题。它只返回一条记录(并且总是相同的记录),然后用于查询的其余部分。如果不知道您的表结构,将很难进一步帮助您。

标签: php mysql join aggregate-functions


【解决方案1】:

这里有一个解决方案。我认为这不是最有效的解决方案,但应该可以。请注意,我将Topics SELECT 移到了第一行。

SELECT `forums`.*, 
        Count(topics.id) threads, 
        Count(replies.id) replies, 
        `users`.`url` user_url, 
        `users`.`name` user_name,
        `ranks`.`name` user_rank,
        (SELECT `topics`.`url` 
         FROM `topics` 
         WHERE `topics`.`f_id` = `forums`.`id` 
         ORDER BY `created` DESC LIMIT 1) topic_url,
        (SELECT  `topics`.`name`
         FROM `topics` 
         WHERE `topics`.`f_id` = `forums`.`id` 
         ORDER BY `created` DESC LIMIT 1) topic_name 
 FROM (`forums`) 
 LEFT JOIN `topics` ON `topics`.`f_id` = `forums`.`id`   
 LEFT JOIN `replies` ON `replies`.`t_id` = `topics`.`id`  
 LEFT JOIN `users` ON `users`.`id` = `topics`.`a_id`  
 LEFT JOIN `ranks` ON `users`.`status` = `ranks`.`id`  
 GROUP BY `forums`.`id`

可能更有效的方式

我没有数据来测试这是否更快,但这是另一种方法(我基于ROW_NUMBER() in MySQL。)附带一个字符串,即topics 表不能有重复的f_id,created 组合:

SELECT `forums`.*, 
        Count(topics.id) threads, 
        Count(replies.id) replies, 
        `users`.`url` user_url, 
        `users`.`name` user_name,
        `ranks`.`name` user_rank,
        t.url topic_url,
        t.name topic_name
 FROM (`forums`)  
 LEFT JOIN (SELECT t0.id, t0.f_id, t0.url, t0.name, t0.a_id
            FROM topics AS t0
            LEFT JOIN topics AS t1 ON t0.f_id=t1.f_id AND t1.created>t0.created
            WHERE t1.id IS NULL) AS t
            ON t.f_id = forums.id
 LEFT JOIN `replies` ON `replies`.`t_id` = t.`id`  
 LEFT JOIN `users` ON `users`.`id` = t.`a_id`  
 LEFT JOIN `ranks` ON `users`.`status` = `ranks`.`id` 
 GROUP BY `forums`.`id`

试试看,先看看能不能用,再看看是不是更快。我很想收到你的回复。

【讨论】:

  • 谢谢,这正是我一直在寻找的,现在我终于明白了选择部分是如何工作的。现在我不得不问,你会推荐什么是最有效的方法?
  • @user1545982,我已经更新了我的答案,以便为您提供一种可能更快地获得所需内容的方法。请尝试一下。
  • “字段列表”中的未知列“topics.id”我会尽快检查更多内容,还有一些其他的事情要处理。
  • @user1545982,我想我找到了哪里出了问题。其他联接使用topics 表。我将他们的引用切换到t。有空的时候告诉我。
  • 根据 CodeIgniters 内置的输出处理程序,稍后的查询需要更少的时间。大约 5% 到 20%。我认为这是相当多的。我会看看我是否让它与“回复”一起工作,这也是另一个表。感谢您抽出宝贵时间。编辑:嗯,我现在看到我做了一些其他的改变,那些 5% 到 20% 可能在 2% 到 16% 左右,但仍然如此。我还必须保存 created 和 replies.url、replies.name、replies.created。它只是另一个 LEFT JOIN (SELECT r0.id...) 还是?
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2015-05-15
  • 2016-05-17
  • 2020-12-28
  • 2013-03-17
  • 1970-01-01
相关资源
最近更新 更多