Laravel雄辩 - 如何在自定义关系中使用DB raw

时间:2015-10-09 16:19:30

标签: mysql laravel

我有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)

请帮助指出我做错了什么?

4 个答案:

答案 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();