我想显示一个包含最后x(例如5个)博客条目的框。 但我想避免一个非常活跃的用户列出两次。
我的试用归结为:
$stats['blog'] = $this->User->Blog->find('all', array(
'order'=>array('Blog.published' => 'DESC'),
'conditions' => array('Blog.status' => 1),
'contain' => array('User.username'),
'group' => array('User.id'),
'limit' => 5,
));
但是 - 当然 - 它太快组合,没有机会先排序。 由此产生的sql经常丢失用户的最后发布的博客条目,而不是其中一个较旧的博客条目:
SELECT *
FROM `comm_blogs` AS `Blog`
LEFT JOIN `comm_users` AS `User` ON (`Blog`.`user_id` = `User`.`id`)
WHERE `Blog`.`status` = 1
GROUP BY `User`.`id`
ORDER BY `Blog`.`published` DESC LIMIT 5
因此,结果几乎完全错误,因为如果此用户过去曾在博客上发布其他内容,则新博客条目永远不会显示。
如何在分组之前先按已发布的DESC进行排序?还是有另一种方便的方法吗? THX
表格的结构:
用户:
- id
- username
博客:
- id
- user_id
- published (datetime)
- title
- content
- status
@gerald:
似乎MYSQl不喜欢这样的子查询:
语法错误或访问冲突:1235此版本的MySQL尚不支持' LIMIT& IN / ALL / ANY / SOME子查询'
SELECT `User`.`id`, `User`.`username`, `Blog`.`id`, `Blog`.`headline`, `Blog`.`published`, `UserInfo`.`gender`, `UserInfo`.`id` FROM `comm_blogs` AS `Blog`
LEFT JOIN `comm_users` AS `User` ON (`Blog`.`user_id` = `User`.`id`)
LEFT JOIN `comm_user_infos` AS `UserInfo` ON (`Blog`.`user_id` = `UserInfo`.`id`)
WHERE `User`.`active` = '1' AND `Blog`.`status` = 1 AND `Blog`.`id` IN (
SELECT `LastBlog`.`id`, MAX(`LastBlog`.`published`) as last
FROM comm_blogs AS LastBlog WHERE `LastBlog`.`status` = 1
GROUP BY `LastBlog`.`user_id` ORDER BY last DESC LIMIT 5
)
ORDER BY `Blog`.`published` DESC
如果我省略了subqery限制:
Cardinality violation: 1241 Operand should contain 1 column(s)
答案 0 :(得分:1)
使用子查询似乎可行 - 使用这个小技巧:
$options = array(
'fields' => array('MAX(SubBlog.created)'),
'conditions' => array('SubBlog.user_id = Blog.user_id')
);
$subquery = $this->subquery('all', $options);
$options = array(
'order'=>array($this->alias.'.published' => 'DESC'),
'conditions' => array(
'User.active' => 1,
'Blog.status' => self::STATUS_ACTIVE,
'Blog.published = ' . $subquery
),
'contain' => array('User.username'),
'fields' => array(
'User.id', 'User.username',
'Blog.id', 'Blog.headline', 'Blog.published'
),
'limit' => $limit,
);
return $this->find('all', $options);
subquery()是一个AppModel方法: https://github.com/dereuromark/tools/blob/2.0/Lib/MyModel.php#L405
答案 1 :(得分:0)
在不知道表结构的情况下,这是相当困难的,但是,这应该给你一个起点:
SELECT `User`.`id`, max(`Blog`.`published`)
FROM `comm_blogs` AS `Blog`
LEFT JOIN `comm_users` AS `User` ON (`Blog`.`user_id` = `User`.`id`)
WHERE `Blog`.`status` = 1
GROUP BY `User`.`id`
ORDER BY 2 DESC LIMIT 5
通过选择每次使用的最大发布日期然后排序,您将获得不同用户的5个最新帖子的列表。然后,您将需要第二个查询来获取内容。
答案 2 :(得分:0)
SELECT *
FROM `comm_blogs` AS `Blog`
LEFT JOIN `comm_users` AS `User` ON (`Blog`.`user_id` = `User`.`id`)
WHERE `Blog`.`status` = 1
AND blog.id IN (
SELECT lastblog.id, max(lastblog.published) as lastpost
FROM comm_blogs AS lastblog
WHERE lastblog.status = 1
GROUP BY lastblog.user_id
ORDER BY lastpost DESC LIMIT 5)
我认为这会奏效;但是,我还没有测试过SQL。
正如您所看到的,内部SQL获得了具有唯一用户的最后五个博客条目。外部SQL根据blog.id获取与这些条目相关的剩余信息。
答案 3 :(得分:0)
如果你尝试使用这个视图怎么样,但它有点奇怪的解决方案,如:
CREATE VIEW comm_blogs_publish_desc AS SELECT `User`.`id` AS `userid`, *
FROM `comm_blogs` AS `Blog`
LEFT JOIN `comm_users` AS `User` ON (`Blog`.`user_id` = `User`.`id`)
WHERE `Blog`.`status` = 1
ORDER BY `Blog`.`published` DESC;
然后您可以将它用于原始查询:
SELECT *
FROM comm_blogs_publish_desc
GROUP BY `userid` LIMIT 5;
这有点奇怪,因为你仍然需要创建视图,但是当它被userid分组时你会确定它已经按发布日期对DESC进行了排序,因为视图已经像虚拟表一样,但它会是理想的,如果你指定哪些列你真正需要,因为如果你只是使用'*'来显示表中的所有列,那么某些列名可能会有冲突(来自其他表的列名相同)。
我看到您在查询时遇到的新更新问题出现了,因为您在IN语句中使用了2个列(它只接受1个列的子查询,当您在其上使用2个或更多列时会返回错误,从而导致基数问题)这样更新:
SELECT `User`.`id`, `User`.`username`, `Blog`.`id`, `Blog`.`headline`, `Blog`.`published`, `UserInfo`.`gender`, `UserInfo`.`id` FROM `comm_blogs` AS `Blog`
LEFT JOIN `comm_users` AS `User` ON (`Blog`.`user_id` = `User`.`id`)
LEFT JOIN `comm_user_infos` AS `UserInfo` ON (`Blog`.`user_id` = `UserInfo`.`id`)
WHERE `User`.`active` = '1' AND `Blog`.`status` = 1 AND `Blog`.`id` IN (
SELECT `LastBlog`.`id`
FROM comm_blogs AS LastBlog WHERE `LastBlog`.`status` = 1
GROUP BY `LastBlog`.`user_id` ORDER BY last DESC
)
ORDER BY `Blog`.`published` DESC LIMIT 0, 5;
然后将限制转移到主查询而不是子查询以避免上一个问题: 语法错误或访问冲突:1235此版本的MySQL尚不支持'LIMIT& IN / ALL / ANY / SOME子查询'
)