Adding raw query to eloquent relationship - php

I am developing an application in Laravel 5.6 I'm having a simple table with following columns:
company_id project_id company_role_id company_specialisation_id
And this represents the model AssociateCompanies, which has relation of company, project, role, specialisation now I am having some query to get the attribute:
$companies = AssociateCompany::whereHas('company', function ($q) use ($request) {
$q->whereHas('projectOwners', function ($q) use($request) {
$q->where('slug', $request->slug);
});
})->groupBy('company_id', 'company_specialisation_id')->with('company', 'role', 'specialisation');
I want to collect all unique fields with their counts from two columns company_id and specialisation_id, but groupBy is not giving me proper the results so I am unbale to proceed further:
SQLSTATE[42000]: Syntax error or access violation: 1055 Expression #1 of SELECT list is not in GROUP BY clause and contains nonaggregated column 'conxn.project_associate_company.id' which is not functionally dependent on columns in GROUP BY clause; this is incompatible with sql_mode=only_full_group_by (SQL: select * from project_associate_company where exists (select , (select count() from project_associate_company where companies.id = project_associate_company.company_id and project_associate_company.deleted_at is null) as associated_projects_count from companies where project_associate_company.company_id = companies.id and exists (select * from projects inner join project_owner_relation on projects.id = project_owner_relation.project_id where companies.id = project_owner_relation.company_id and slug = lodha-patel-estate-tower-a-b-mumbai and projects.deleted_at is null) and companies.deleted_at is null) and project_associate_company.deleted_at is null group by company_id, company_specialisation_id)"
So I tried running raw queries like this:
$companies = AssociateCompany::whereHas('company', function ($q) use ($request) {
$q->whereHas('projectOwners', function ($q) use($request) {
$q->where('slug', $request->slug);
});
})->selectRaw(DB::raw('COUNT(*) AS count GROUP BY company_id , company_specialisation_id'))
->with('company', 'companyRole', 'specialisation')->get();
SQLSTATE[42000]: Syntax error or access violation: 1064 You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near 'GROUP BY company_id , company_specialisation_id from project_associate_company' at line 1 (SQL: select COUNT(*) AS count GROUP BY company_id , company_specialisation_id from project_associate_company where exists (select , (select count() from project_associate_company where companies.id = project_associate_company.company_id and project_associate_company.deleted_at is null) as associated_projects_count from companies where project_associate_company.company_id = companies.id and exists (select * from projects inner join project_owner_relation on projects.id = project_owner_relation.project_id where companies.id = project_owner_relation.company_id and slug = lodha-patel-estate-tower-a-b-mumbai and projects.deleted_at is null) and companies.deleted_at is null) and project_associate_company.deleted_at is null)"
Suggest me better way to get this. Thanks.

Initially I want to notice you can not "group by" inside the "select" statement.
So you can not aggregate the non-aggregated columns. This means is grouped fields can be has got multiple "role" so you can not "load" the "roles". The query should be like the one of the follows:
AssociateCompany::whereHas('company', function ($q) use ($request) {
$q->whereHas('projectOwners', function ($q) use($request) {
$q->where('slug', $request->slug);
});
})->select('company_id', 'company_specialisation_id', \DB::raw('COUNT(*) as cnt'))
->groupBy('company_id', 'company_specialisation_id')
->with('company', 'specialisation');
Or :
AssociateCompany::whereHas('company', function ($q) use ($request) {
$q->whereHas('projectOwners', function ($q) use($request) {
$q->where('slug', $request->slug);
});
})->select('company_id', 'company_specialisation_id', 'company_role_id', \DB::raw('COUNT(*) as cnt'))
->groupBy('company_id', 'company_specialisation_id', 'company_role_id')
->with('company', 'specialisation', 'role');
My suggestions are like this but I think you can solve it with raw MySQL queries rather than use to Eloquent.

Related

How Get Count in Join Query in Laravel

I want to convert the following SQL to Laravel.
SELECT COUNT('uc.*') AS count_down, bs.brand_name
FROM `user_activities` AS uc
JOIN brands AS bs ON uc.brand_id = bs.id
GROUP BY uc.brand_id
ORDER BY count_down DESC
LIMIT 5
But when doing this:
$top_donwload_list = DB::table('user_activities')
->leftJoin('brands', 'brands.id', '=', 'user_activities.brand_id')
->selectRaw('brands.*, brands.brand_name, brands.id, count(user_activities.action_type) as user_activitiesCount')
->groupBy('user_activities.brand_id')
->get();
I get this error:
SQLSTATE[42000]: Syntax error or access violation: 1055 'colorworld.brands.id' isn't in GROUP BY (SQL: select brands.*, brands.brand_name, brands.id, count(user_activities.action_type) as user_activitiesCount from user_activities left join brands on brands.id = user_activities.brand_id group by user_activities.brand_id)
I tried to set 'strict' => true, in database.php but I get the same error in Laravel 5.7.
Update:- database table
If I understood your question correctly, you are trying to find the count of user activities grouped by a brand's name. Also you want the top 5 records ordered by the ones with the most user activities.
So, the following should work:
$top_donwload_list = DB::table('user_activities')
->selectRaw("brands.brand_name, COUNT('user_activities.*') as user_activitiesCount")
->join('brands', 'brands.id', '=', 'user_activities.brand_id')
->groupBy('brands.brand_name')
->orderBy('user_activitiesCount', 'desc')
->take(5)
->get();
You can use Laravel Eloquent. I Assume that the relationship between brand and user_activities is one to many and Here, the "Brand" is the model of the brand entity.
$count = Brand::leftJoin
('user_activities', function($join_brands){
$join_brands-> on
('brands.id', '=','user_activity.brand_id');
)->orderBy('user_activities.count_down','desc ')
->groupBy('user_activities.brand_id')->count();

Laravel Eloquent and Mysql join a table IF another join is null

Three main tables:
products
advertisers
locations
Two pivot tables:
advertisers_locations
products_locations
Relationships:
A product belongs to an advertiser and an advertiser has many locations (Locations it can ship products to)
A product can also have it own set of locations that override the advertiser locations (Some products have delivery restrictions)
What I need to do is:
Select all products
Check if products_locations table for product ID and join it.
If it does not exist then join the advertisers locations table
Is this possible to do in one query and using eloquent? Here's my code - struggling with the conditional:
public function scopeWhereShippableToLocation($query)
{
$location_id = session('location_id');
$query->where(function ($q) use ($location_id) {
$q->join('products_locations', 'products_locations.product_id', '=', 'products.id')
->where('products_locations.location_id', '=', $location_id);
});
$query->orWhere(function ($q) use ($location_id) {
$q->join('advertisers_locations', 'advertisers_locations.advertiser_id', '=', 'products.advertiser_id')
->where('advertisers_locations.location_id', '=', $location_id);
});
//dd($q->toSql());
return $query;
}
This is currently producing a MySQL error:
Column not found: 1054 Unknown column 'products_locations.location_id' in 'where clause' (SQL: select `products`.*,
I think I have a solution for you using eloquent, rather than the query builder. You need to check to see if the relationship exists, if not you need another query. This can be done using the following:
public function scopeWhereShippableToLocation($query)
{
$location_id = session('location_id');
// WhereHas check to see if a relationship exists, IE: The pivot table
// orWhereHas will be checked if the first where does not exist
$query->whereHas('products_locations', function ($q) use ($location_id) {
$q->where('location_id', $location_id);
})->orWhereHas('advertisers_locations', function ($q) use ($location_id) {
$q->where('location_id', $location_id);
});
return $query;
}
This should work providing that your Products, Advertisers and Locations relationship methods are set up.

How to write mysql query in laravel 5.4?

I am new to laravel and i want to write mysql query in laravel 5.4.
query is like :
note: avoid column names..
SELECT *
FROM (SELECT DISTINCT *
FROM messages
WHERE (from_id=1 OR to_id=1)
ORDER BY created DESC) as m
GROUP BY `from_id`
I tried but gives error.
$messages = DB::table('messagetbl')
->select('*')
->Where(function($query) use ($userid){
$query->distinct()
->where('senderid',$userid)
->orWhere('receiverid',$userid)
->orderBy('datetime','desc');
})
->groupBy('senderid')
->get();
Error:
SQLSTATE[42000]: Syntax error or access violation: 1055
Expression #1 of SELECT list is not in GROUP BY clause and contains
nonaggregated column 'db.messagetbl.id' which is not functionally
dependent on columns in GROUP BY clause; this is incompatible with
sql_mode=only_full_group_by (SQL: select * from messagetbl where
(senderid = 8 or receiverid = 8) group by senderid)
Thanks in advance.
I believe something like this:
DB::table('messages')
->select('*')
->where('form_id', '=', 1)
->orWhere('to_id', '=', 1)
->orderBy('created', 'desc')
->groupBy('form_id')
->distinct()
->get();

Laravel Join multiple table not working

I'm having an issue on Laravel 5.4 when I try to use only one join it works ok and returns correct data, but their add another join it doesn't work.
$data = Player::select(DB::raw('CONCAT(familyName,", ",firstName) AS fullName'))
->where('firstname', 'like', '%'.$search.'%')
->orWhere('familyName', 'like', '%'.$search.'%')
->orderBy('familyName', 'asc')
->join('teams', 'players.primaryClubId', '=', 'teams.clubId')
->join('person_competition_statistics', 'players.personId', '=', 'person_competition_statistics.personId')
->addSelect(['players.*', 'teams.teamName', 'teams.teamNickname', 'teams.teamCode'])
->get()
->unique() //remove duplicates
->groupBy(function($item, $key) { //group familyName that starts in same letter
return substr($item['familyName'], 0, 1);
})
->map(function ($subCollection) {
return $subCollection->chunk(4); // put your group size
});
return $data;
Returned Error:
QueryException in Connection.php line 647:
SQLSTATE[23000]: Integrity constraint violation: 1052 Column 'familyName' in field list is ambiguous (SQL: select CONCAT(familyName,", ",firstName) AS fullName, `players`.*, `teams`.`teamName`, `teams`.`teamNickname`, `teams`.`teamCode` from `players` inner join `teams` on `players`.`primaryClubId` = `teams`.`clubId` inner join `person_competition_statistics` on `players`.`personId` = `person_competition_statistics`.`personId` where `firstname` like %% or `familyName` like %% order by `familyName` asc)
If you are joining table then you should give table alias. like team as t , players as p and then column name like p.playername

ModelSearch Query error in Yii2

I have two tables project and workload. I want show user in some project that added in Workload, and anothers member in this project (I called Team Member of that Project), too.
My idea is join 2 tables project and workload with user_id condition to take projects of user have user_id, then, from that will join with workload table again to take data from project of user have that user_id and user_id of team member will have that projects.
That my code in WorkloadSearch.php
public function searchWorkloadofUser($params) {
$user_id = Yii::$app->user->id;
$query = Workload::find()
->select(['workload.project_id', 'workload.commit_time', 'project.project_name', 'workload.from_date', 'workload.to_date', 'workload.workload_type', 'workload.comment'])
->join('INNER JOIN', 'project', 'workload.project_id=project.id')
->where('workload.user_id = '.$user_id)->orderBy('project.project_name ASC')->distinct();
$query->join('INNER JOIN','workload', 'project.id = workload.project_id')->distinct();
}
I don't understand why appeared error:
SQLSTATE[42000]: Syntax error or access violation: 1066 Not unique table/alias: 'workload'
The SQL being executed was: SELECT COUNT(*) FROM (SELECT DISTINCT `workload`.`project_id`, `workload`.`commit_time`, `project`.`project_name`, `workload`.`from_date`, `workload`.`to_date`, `workload`.`workload_type`, `workload`.`comment` FROM `workload` INNER JOIN `project` ON workload.project_id=project.id INNER JOIN `workload` ON project.id = workload.project_id WHERE workload.user_id = 20) `c`
like the others said: You need an alias. Your error messages tells you:
SQLSTATE[42000]: Syntax error or access violation: 1066 Not unique table/alias: 'workload'
This is beacause you joined your table worload to your workload table:
$query = Workload::find() //your `workload` table
->select([
....
])
->join('INNER JOIN', 'project p'], 'workload.project_id=p.id')
->where('workload.user_id = '.$user_id)
->orderBy('p.project_name ASC')
->distinct();
$query->join('INNER JOIN','workload', 'project.id = workload.project_id') //join the `workload` table to the `workload` table
->distinct();
When you want to join a table to itself, you have to define an alias at least for the joining table.
I would recommend you to quote the tablenames and columns whis is described in the Yii2 guide here and do not concat strings but bind params like it's described here and here. This code should work for you (not tested):
$query = Workload::find() //your `workload` table
->select([
'{{workload}}.[[project_id]]', //quoting tablenames and columns
'{{%workload}}.[[commit_time]]', //add '%' when you're using table prefix
...
])
->join('INNER JOIN', 'project p'], 'workload.project_id=p.id')
->where('workload.user_id' = :user_id, [':user_id' => $user_id]) //You should bind params when use string format
//or use hash format
//->where(['workload.user_id' => $user_id])
...
$query->join('INNER JOIN','workload w2', 'project.id = w2.project_id') //Use the alias `w2` to join the `workload` table to the `workload` table
->distinct();
You need to give the user table an alias the second time you join to it
e.g.
SELECT workload.project_id, workload.commit_time, p.project_name, ...
FROM workload
LEFT JOIN project p ON p.id = workload.project_id
WHERE workload.user_id = '1'
Your solution should be (untested):
public function searchWorkloadofUser($params)
{
$user_id = Yii::$app->user->id;
$query = Workload::find()
->select(['workload.project_id', 'workload.commit_time', 'p.project_name', 'workload.from_date', 'workload.to_date', 'workload.workload_type', 'workload.comment'])
->join('INNER JOIN', 'project p'], 'workload.project_id=p.id')
->where('workload.user_id = '.$user_id)->orderBy('p.project_name ASC')->distinct();
...

Categories