Невозможно преобразовать SQL запрос в laravel красноречивый - PullRequest
0 голосов
/ 11 января 2020

У меня есть этот запрос, который получит сколько голосов пользователей с каждой звездой

SELECT stars, COUNT(*) AS rate FROM product_user where product_id = 1 GROUP BY(stars)

результат этого запроса

stars | rate
_____________
 2    |  3
 5    |  4

, но я не могу преобразовать его в laravel eloquent

это моя попытка, но появляется ошибка

Product::find($id)->votes()->selectRaw('count(*) as rate, stars')
  ->groupBy('stars')
  ->get();

Сообщение об ошибке

SQLSTATE[42000]: Syntax error or access violation: 1055 Expression #1 of SELECT list is not in GROUP BY clause and contains nonaggregated column 'roya.users.id' which is not functionally dependent on columns in GROUP BY clause; this is incompatible with sql_mode=only_full_group_by (SQL: select `users`.`id`, `first_name`, `last_name`, count(*) as rate, stars, `product_user`.`product_id` as `pivot_product_id`, `product_user`.`user_id` as `pivot_user_id`, `product_user`.`stars` as `pivot_stars`, `product_user`.`feedback` as `pivot_feedback`, `product_user`.`created_at` as `pivot_created_at`, `product_user`.`updated_at` as `pivot_updated_at` from `users` inner join `product_user` on `users`.`id` = `product_user`.`user_id` where `product_user`.`product_id` = 1 group by `stars`)

Модель продукта

class Product extends Model {
 public function votes()
 {
        return $this->belongsToMany(User::class)
            ->using('App\Review')
            ->select('users.id', 'first_name', 'last_name')
            ->withPivot(['stars', 'feedback'])
            ->withTimeStamps();
 }
}

Ответы [ 2 ]

1 голос
/ 11 января 2020

Что вы можете сделать, это добавить отношение ratings к вашей модели Продукта, которое равно hasMany между Product и Rating:

public function ratings()
{
    return $this->hasMany(Rating::class)
        ->select('stars', 'product_id')
        ->selectRaw('count(*) as rate')
        ->groupBy('stars', 'product_id');
}

Тогда ваш запрос будет выглядеть примерно так: :

$product = Product::with('rating')->find(1);

Этот продукт будет выглядеть примерно так:

{
   "id":1,
   ...
   "ratings":[
      {
         "stars":2,
         "product_id":1,
         "rate":1
      },
      {
         "stars":3,
         "product_id":1,
         "rate":2
      },
      {
         "stars":4,
         "product_id":1,
         "rate":4
      },
      {
         "stars":5,
         "product_id":1,
         "rate":3
      }
   ]
}
1 голос
/ 11 января 2020

При использовании сгруппированных запросов выбора SQL позволяет выбирать только агрегированные функции или столбцы, специально перечисленные в разделе GROUP BY. Ваше отношение votes() добавляет дополнительные столбцы выбора к вашему запросу ('users.id', 'first_name' и 'last_name'), и они вызывают ошибку. Это происходит потому, что метод selectRaw не заменяет ранее выбранные столбцы, а использует метод addSelect() для добавления необработанных поверх существующих.

В вашем случае действительно сложно использовать Eloquent здесь, когда вы только Вам нужны данные агрегированного подсчета для определения c голосов продуктов.

Просто добавьте метод getVotesCountByStars к вашей модели Product и используйте построитель запросов Laravel generi c через фасад DB:

public function getVotesCountByStars()
{
    return DB::table('product_user')
        ->where('product_id', $this->id)
        ->selectRaw('count(*) as rate, stars')
        ->groupBy('stars')
        ->orderBy('stars', 'asc')
        ->get()
        ->pluck('rate', 'stars')
        ->toArray();
}

Таким образом, вы точно увидите, какой запрос сгенерирован, и никаких дополнительных затрат не производится (в моем примере будет возвращен ассоциативный массив со звездами в качестве ключей и подсчетами в качестве значений).

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...