SQLSTATE[42000]: Syntax error or access violation: 1055 when using groupBy with hasManyThrough relation in Laravel - mysql

When using groupBy on hasMany relation it is work fine but
when using groupBy on hasManythrough relation
in my controllr :
public function main()
{
# code...
$user = Auth::user();
$results = [
'vacations' => $user->vacations()->groupBy('type')->selectRaw('sum(days) as days,sum(mins) as mins, type')->get(), //works fine
'vactionRegisterd' => $user->vacationsRegisterd()->groupBy('type')->selectRaw('sum(days) as days,sum(mins) as mins, type')->get(), //works fine
'empVacations'=>$user->empVacations, //work fine
'employees_vacations'=>$user->empVacations()->groupBy('type')->selectRaw('sum(days) as days,sum(mins) as mins, type')->get(),//gives an error
];
return view('dashboard.dashboard', ['results' => $results]);
}
I have this error :
SQLSTATE[42000]: Syntax error or access violation: 1055
'hrweb.users.manager_id' isn't in GROUP BY (SQL: select sum(days) as
days,sum(mins) as mins, type, users.manager_id as
laravel_through_key from vacations inner join users on
users.id = vacations.user_num where users.manager_id = 5
group by type)I have tow tables users ,vacations
I don't know why (users.manager_id as laravel through key) is used even though I didn't use "users.manager_id" with "groupBy" or "selectRow" method.
My Code in user model :
1- user has many employees where employees are also users with different role and with manager_id != null [user->employees]
/**
* Get all of the employees from user table for the current admin User
*/
public function employees()
{
return $this->hasMany('App\Models\User', 'manager_id');
}
2- user has many vacations [user->vacations]
/**
* Get all of the vacations for the User
*/
public function vacations()
{
return $this->hasMany('App\Models\Vacations', 'user_num', 'id');
}
3- user hasManyThrough vacations [user->employees->vacation]
/**
* Get all of the employees vacations for the User
*/
public function empVacations()
{
return $this->hasManyThrough(Vacations::class, User::class, 'manager_id', 'user_num', 'id', 'id');
}

By reading the Error again ,I noted that Laravel use the foreign key as laravel_through_key in the query in some way.
The problem solved by adding laravel_through_key in the groupBy() method like this :
[...
'employees_vacations'=>$user->empVacations()
-> groupBy('laravel_through_key','user_num','type')
-> selectRaw('sum(days) as days,sum(mins) as mins,user_num, type')->get()
]
But I still think there is a better solution so I will be happy to know your answers ^_^

Related

Laravel ORM query is not displaying correct relationships

I am working on laravel project and I have a query when i gave it where id, it gives me correct relationships but when i use other conditions it did not give me relationships.
This is my controller query
$dogsCheckedIn = Dog::with(['latestActiveVisit'])
->whereNotNull('checked_in')
->whereNull('checked_out')
->orderBy('projected_out_date','asc');
// ->where('id', 21); gives relationship correctly but if i remove it shows the records but did not show me relationship
if(Request::get('ag'))
$dogsCheckedIn->where('appointment_group_id', intval(Request::get('ag')));
$dogsCheckedIn = $dogsCheckedIn->get()
->each(function($dogRecord) {
$dogRecord->record = DogRecord::with('user')->where('dog_id',$dogRecord->id)->whereNotNull('weight')->orderBy('created_at','desc')->first();
});
And this is my model function
public function latestActiveVisit()
{
return $this->hasMany(DogVisits::class, 'dog_id', 'id')
->whereNotNull('checked_in')
->whereNull('checked_out')
->select('id', 'created_at', 'dog_id')
->latest('created_at')->take(1);
}

How to get latest post from threads with several fields?

In my Laravel 5.8/mysql5 app I get latest post from threads like
$forumThreads= ForumThread
::getByForumId($forum_id)
->select(
'forum_threads.*',
\DB::raw(' ( select count('.$prefix.'forum_posts.id) from '.$prefix.'forum_posts where '.$prefix.'forum_posts.forum_thread_id = '.$prefix.'forum_threads.id ) as forum_posts_count'),
\DB::raw(' ( select created_at from '.$prefix.'forum_posts where '.$prefix.'forum_posts.forum_thread_id = '.$prefix.'forum_threads.id order by id desc limit 1) as latest_post_created_at')
)
->orderBy($order_by, $order_direction)
->offset($limit_start)
->take($forum_threads_per_page)
->get();
It works ok, but I need to get several fields for latest post. If I change condition as :
\DB::raw(' ( select created_at, title, slug from '.$prefix.'forum_posts where
I got error :
Cardinality violation: 1241 Operand should contain 1 column(s)
Of there is a way ?
modified block:
In app/ForumThread.php I created
public function latestForumPost()
{
return $this->hasOne('App\ForumPost')->latest();
}
public function forumPosts()
{
return $this->hasMany('App\ForumPost');
}
and in my control I make :
$forumThreads= ForumThread::with('latestForumPost')->withCount('forumPosts')
->getByForumId($forum_id)
->orderBy($order_by, $order_direction)
->offset($limit_start)
->take($forum_threads_per_page)
->get();
foreach( $forumThreads as $next_key=>$nextForumThread ) {
$nextForumThread->latest_post_created_at= $nextForumThread->latestForumPost->created_at;
}
and that works!
But when I try to use $nextForumThread->latestForumPost in my blade.php file :
<tr v-for="nextForumThread, index in forumThreads" :key="nextForumThread.id">
nextForumThread.latestForumPost::{{ nextForumThread.latestForumPost}}
Itdoes not work. Can it be use in blade template?
You can achieve that with a simple relationship.
// ForumThread model
public function latestPost()
{
return $this->hasOne('Post')->latest();
}
public function posts()
{
return $this->hasMany('Post');
}
Now we will use latestPost relationship to get details of latest post per category and posts to get count.
So your refactored query would be:
$forumThreads= ForumThread::with('latestPost')->withCount('posts')
->getByForumId($forum_id)
->orderBy($order_by, $order_direction)
->offset($limit_start)
->take($forum_threads_per_page)
->get();
You can access these data as follow:
foreach ($forumThreads as $thread) {
echo $thread->posts_count; -- to show posts counts per thread.
echo $thread->latestPost->id; -- to access any field from latestPost
}
Reference:
Counting Related Models
Tweaking Laravel Relationship

Laravel: hasMany relationship + where condition fails

I have a Customer Eloquent model. Customer can have multiple WishLists where he / she can add some products. Typical ecommerce functionality.
The point is that Customer can belong to many Users models.
This was easy:
public function users()
{
return $this->belongsToMany(User::class, 'users_sync_customers', 'customer_uuid', 'user_id')
->withTimestamps()
->orderBy('last_name', 'asc');
}
So I can get all Customers assigned for logged in user by
auth()->user()->customers 🎉
As I mentioned, Customer can have multiple Wishlists:
public function wishLists()
{
return $this
->hasMany(WishList::class, 'customer_uuid', 'uuid')
->where('user_id', '=', auth()->user()->id); // <----- this will fail when I log out
}
but WishList is scoped to both Customer UUID and User ID.
Above relationship works but only when I'm logged in obviously.
As soon as I log out the auth()->user()->is is NULL and I get:
ErrorException {#1483 #message: "Trying to get property 'id' of
non-object"
Question: How can I reference in wishLists() the user_id value?
WishList model has this:
public function user()
{
return $this->belongsTo(User::class, 'user_id', 'id');
}
So can I use something like $this->user->id?
edit:
Nope, this also doesn't work.
you must check that the user is logged in?
Auth::check() ? Auth::user()->id : null

Can't store a new row - SQLSTATE[23000]: Integrity constraint violation: 1452 Cannot add or update a child row: a foreign key constraint fails

My clients table and users table are child tables of my businesses table. So both the clients and users table contain a business_id column that refers to the id column of the businesses table:
public function up()
{
Schema::create('clients', function(Blueprint $table)
{
$table->increments('id');
$table->integer('business_id')->unsigned();
$table->foreign('business_id')->references('id')->on('businesses');
$table->string('first_name');
$table->string('last_name');
Etc…
I am able to store a new user, it works fine, but I keep getting this error when trying to store a new row into my clients table :
SQLSTATE[23000]: Integrity constraint violation: 1452 Cannot add or
update a child row: a foreign key constraint fails
(laravel.clients, CONSTRAINT clients_business_id_foreign FOREIGN
KEY (business_id)
Client.php model
/**
* The attributes that are mass assignable.
*
* #var array
*/
protected $fillable = ['business_id', 'first_name', 'last_name'];
/**
* Business where this user works.
*
* #return \Illuminate\Database\Eloquent\Relations\BelongsTo
*/
public function businesses()
{
return $this->belongsTo('App\Business');
}
Business.php model
/**
* Clients that use this business.
*
* #return \Illuminate\Database\Eloquent\Relations\HasMany
*/
public function clients()
{
return $this->hasMany('App\Client','business_id');
}
ClientsController.php
public function store(ClientsRequest $request)
{
var_dump(Auth::user()->business_id);
$clientinfo = Request::all();
Client::create($clientinfo);
$client = new Client;
$client->business_id = Auth::user()->business_id;
$client->first_name = $clientinfo['first_name'];
$client->last_name = $clientinfo['last_name'];
//$client->save();
$business->clients()->save($client);
$last_inserted_id = $data->id;
return redirect('clients/'.$last_inserted_id.'/edit');
The only thing I’m not sure is the way I’m retrieving the business_id (from the users table), via Auth. When I var_dump that value, I get :
string(1) "7"
I know the id value is 7 in my businesses table, that’s what I’m looking for, but not sure if it should be converted to integer.
And, not sure if I have to save using :
$client->save();
Or
$business->clients()->save($client);
Thanks
Both following are correct ways, but first one is more Laravel than later,
public function store(ClientsRequest $request)
{
$client = new Client([
'first_name' => $request->get('first_name'),
'last_name' => $request->get('last_name'),
]);
$client = Business::findOrFail(Auth::user()->business_id)
->clients()
->save($client);
return redirect('clients/'.$client->id.'/edit');
}
P.S. above business_id will be automatically added to client by Eloquent
Other way is like you did, where you are inserting a business_id manually.
public function store(ClientsRequest $request)
{
$clientinfo = Request::all();
$client = Client::create([
'business_id' => Auth::user()->business_id;
'first_name' => $clientinfo['first_name'];
'last_name' => $clientinfo['last_name'];
]);
return redirect('clients/'.$client->id.'/edit');
}
You are receiving error because of following statement in your code,
Client::create($clientinfo);
Above statement will attempt to create a database entry without business_id which is a foreign key and should be supplied but wasn't and hence error.
And you don't have to worry about type-conversion between int<->string, PHP is very good at it.
Read More

Eloquent where clause to use related model's column when using with() -laravel 4

I have 2 models
Truck
class Truck extends \Eloquent {
// Add your validation rules here
public static $rules = [
'trucktype_id' => 'required',
'weight'=> 'required',
'truck_no'=> 'required'
];
// Don't forget to fill this array
protected $fillable = ['trucktype_id','weight','picture_path','remarks','truck_no'];
public function TruckType(){
return $this->belongsTo('TruckType','trucktype_id');
}
}
TruckType
class Trucktype extends \Eloquent {
// Add your validation rules here
public static $rules = array(
'type' => 'required|unique:trucktypes,type',
'max_weight' => 'required'
);
// Don't forget to fill this array
protected $fillable = ['type','max_weight'];
}
I need to lookup related table records i.e TruckType
$trucksobj = Truck::with('TruckType');
if($truck_no!="")
$trucksobj->where("truck_no",'=',$truck_no);
if($start_date!="" && $end_date!="")
$trucksobj->whereBetween('created_at', array($start_date, $end_date));
if($truck_type!="")
$trucksobj->where("trucktype_id",'=',$truck_type);
if($overweight=="on")
$trucksobj->where('TruckType.max_weight', '>=', 0);
But the above query didnt resolve TruckType.max_weight and throws following error
SQLSTATE[42S22]: Column not found: 1054 Unknown column 'TruckType.max_weight' in 'where clause' (SQL: select count(*) as aggregate from trucks where TruckType.max_weight >= 0)
I think you misunderstand how with() actually works. It is only used to alleviate the N+1 query problem, and does not make the contents of the table available for querying. After your first query has ran to select all of the trucks, the with() simply causes the following query to be automatically ran:
select * from TruckType where TruckType.id in (...)
Here the list at the end will contain all of the different truck.trucktype_id values that were found in your first query, and then they'll automatically be available for you to use via $truck->TruckType->{property} etc.
Now, if you actually have a look at the query that's being generated for you, you can clearly see that there is no TruckType table referenced anywhere:
select count(*) as aggregate from trucks where TruckType.max_weight >= 0
This is why the error is being thrown.
You have two options:
(1) Use a join
$trucksobj = Truck::with('TruckType')->join('TruckType', 'truck.trucktype_id', '=', 'TruckType.id')->where('TruckType.max_weight', '>=', 0);
(2) Use whereHas() to place a constraint on your relationship
$trucksobj = Truck::with('TruckType')->whereHas('TruckType', function($q) {
$q->where('max_weight', '>=', 0);
});
If you don't actually need to know anything about the truck type, and you only want to use it to sieve through the trucks, then you can get rid of with('TruckType') and just keep the rest of the query.