我有laravel模型: 发表评论。正常情况下,帖子会有很多评论 如下表:
Posts table
--------------------------------------
|id |title | |
--------------------------------------
|1 |test |
comments table:
--------------------------------------
|id |post_id | created_at |
--------------------------------------
|1 |1 |2015-09-12 09:01:02 |
--------------------------------------
|2 |1 |2015-09-12 09:03:02 |
现在我想查询从当前日期回到过去7天的评论数最多的帖子。 这是我在Laravel Controller中的代码:
$posts= Post::whereHas(
'comments', function ($q) {
$q->select(DB::raw("DATE_FORMAT(created_at,'%Y-%m-%d %H:%i:%s')"),'post_id',DB::raw('count(*) as cmt_count'))
->where(DB::raw('`comments`.`created_at` BETWEEN NOW()-INTERVAL 8 DAY AND NOW()'))
->groupBy('post_id');
})
->take(5)->get();
得到了错误:
QueryException in Connection.php line 651: SQLSTATE[21000]: Cardinality violation: 1241 Operand should contain 3 column(s) (SQL: select * from `posts` where (select DATE_FORMAT(created_at,'%Y-%m-%d %H:%i:%s'), `post_id`, count(*) as cmt_count from `comments` where `comments`.`post_id` = `posts`.`id` and `comments`.`created_at` BETWEEN NOW()-INTERVAL 8 DAY AND NOW() is null group by `post_id`) >= 1 limit 5)
请帮助指出我做错了什么?
答案 0 :(得分:1)
行。经过上述建议的挖掘后,我自己解决了这个问题。 在这里发布这个答案,任何有相同问题的人都会发现它有用。 下面是查询(假设您已经设置了关系)
$posts = Post::select(DB::raw('posts.id,posts.title,count(*) as cmnt_count'))
->join('comments',function($q){
$q->on('posts.id','=','comments.post_id')
->where(DB::raw("DATE_FORMAT(comments.created_at,'%Y-%m-%d %H:%i:%s')),'>=',Carbon::now()->subDays(7));
})->groupBy('posts.id')
->orderBy('cmnt_count')->get();
现在我可以得到我想要的东西:检索7天内有评论的所有帖子,并按评论数量排序。
答案 1 :(得分:0)
我不确定SQL的整个逻辑。但问题在于以下部分:
int main () {
B<A> b;
b.func ();
b.print ();
}
现在,您的查询构建器响应此部分的部分是:
`comments`.`created_at` BETWEEN NOW()-INTERVAL 8 DAY AND NOW() is null
这很清楚 - 你想使用raw where表达式。但是方法通常需要2或3个参数。
为什么不尝试用whereRaw替换它?
您的构建器将如下所示:
where(DB::raw('`comments`.`created_at` BETWEEN NOW()-INTERVAL 8 DAY AND NOW()'))
这应该使用whereRaw参数作为最终SQL的原始部分。
如果这可以解决您的问题,请告诉我。
小心
答案 2 :(得分:0)
不要使用$q->select()
,whereHas()
期望查询返回一个数字(通常为count(*))。
whereHas()
可能会选择其相对记录的计数大于1的父记录。
尝试->toSql()
而不是->take(5)->get()
来查看原始SQL查询。
======编辑========
我认为你可以做这样的事情。
$posts= Post::whereHas(
'comments', function ($q) {
$q->where(DB::raw('`comments`.`created_at` BETWEEN NOW()-INTERVAL 8 DAY AND NOW()'))
->groupBy('post_id');
})
->with('comment_counts')
->take(5)->get();
或者如果您想使用 Carbon :
$q->where('created_at', '>=', Carbon::now()->addWeek(-1))
在你的模特中:
class Post extends Model {
//...
public function comment_counts() {
return $this->hasMany('App\Comment')->select([ DB::raw("DATE_FORMAT(created_at,'%Y-%m-%d %H:%i:%s')"),'post_id',DB::raw('count(*) as cmt_count') ]);
}
}
答案 3 :(得分:0)
尝试此查询,我没有尝试,但它必须工作
$posts= Post::whereHas(
'comments', function ($q) {
$q->select(DB::raw("DATE_FORMAT(created_at,'%Y-%m-%d %H:%i:%s')"),'post_id',DB::raw('count(*) as cmt_count'))
->groupBy('post_id')
->where('created_at','>',DB::raw('date_sub(CURDATE(), INTERVAL 1 WEEK)'))
->where(DB::raw('DATE(created_at)'),'<=',DB::raw('CURDATE()'));
})
->take(5)->get();