2015-10-09 6 views
0

У меня есть модели laravel: Сообщение и комментарий. Как нормальный, пост будет иметь много комментариев таблицы, как показано ниже:Laravel eloquent - как использовать DB raw внутри пользовательских отношений

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 контроллера:

$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

Я не уверен во всей логике вашего SQL. Но проблема заключается в следующей части:

`comments`.`created_at` BETWEEN NOW()-INTERVAL 8 DAY AND NOW() is null 

Теперь часть вашего построитель запросов в ответ на этот кусок:

where(DB::raw('`comments`.`created_at` BETWEEN NOW()-INTERVAL 8 DAY AND NOW()')) 

Это вполне понятно - вы хотите использовать в сыром виде, где выражение. но где метод обычно принимает 2 или три параметра.

Почему бы вам не попробовать заменить его на whereRaw?

Ваш строитель будет выглядеть следующим образом:

$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')) 
      ->whereRaw('`comments`.`created_at` BETWEEN NOW()-INTERVAL 8 DAY AND NOW()') 
       ->groupBy('post_id'); 

     }) 
     ->take(5)->get(); 

Это следует использовать аргумент whereRaw в качестве исходного куска окончательного SQL.

Сообщите мне, если это решит вашу проблему.

уход Take

+0

благодарю за ваш ответ, но ваш запрос не работает, как ожидайте. Bellow - это ответ на ошибку от laravel: 'QueryException в строке Connection.php 651: SQLSTATE [21000]: нарушение кардинальности: 1241 Операнд должен содержать 3 столбца (SQL: выберите * из сообщений, где (выберите DATE_FORMAT (created_at, '% Y -% m-% d% H:% i:% s '), post_id, count (*) как cmt_count из комментариев, где comments.post_id = post.id и comments.created_at МЕЖДУ СЕЙЧАС() - ИНТЕРВАЛ 8 ДЕНЬ И СЕЙЧАС () group by post_id)> = 1 limit 5) ' – user804293

0

Не используйте $q->select(), whereHas() ожидая запрос возвращает номер (как правило, рассчитывать (*)). whereHas() может выбрать родительские записи, где отсчет его относительных записей больше, чем 1.

Попробуйте ->toSql() вместо ->take(5)->get() увидеть ваш необработанный запрос SQL.

====== EDIT ========

Я думаю, что вы могли бы сделать что-то вроде этого.

$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') ]); 
    } 
} 
+0

Да, у меня может быть Laravel, чтобы вернуть мне необработанный запрос, используя DB :: getQueryLog() – user804293

+0

Вы увидите, что' whereHas' преобразуется в подзапрос '.. . И (SELECT .... FROM

WHERE ...)> = 1 ... 'поэтому, когда вы помещаете' -> select() ', которые возвращают более 1 поля, он выдает ошибку SQL. Это не проблема «DB :: raw()», а скорее ошибка SQL-запроса. И если код работает нормально, он не будет возвращать вам «count» или «created_at», так как вы SELECT count (*) внутри подзапроса, а не в самом запросе «posts». –

+0

So. Есть ли у вас предложение сделать то, что мне нужно, как указано в моем вопросе? – user804293

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(); 
+0

Ваше решение не отличается от приведенных выше ответов и комментариев. не собираюсь работать. – user804293

0

ОК. после некоторого копания с предложениями выше, я сам решаю проблему. Опубликуйте этот ответ здесь для тех, у кого такая же проблема может оказаться полезной. ниже является запрос (предполагается, что вы уже настроить отношения)

$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 дней и сортировка по количеству комментариев.

Смежные вопросы