Laravel query builder not replacing question mark - laravel

I'm running the following query:
return $this->hasMany('App\Task', 'company')
->whereNotIn('id', function($query)
{
$query->from('tasks')->join('projects', function($join)
{
$join->on('projects.id', '=', 'tasks.project')
->where('projects.status', '=', Project::STATUS_ARCHIVED);
})
->select('tasks.id');
});
But if I output the whole raw query I get the following:
select * from `tasks` where `tasks`.`company` = 1 and `id` not in (select `tasks`.`id` from `tasks` inner join `projects` on `projects`.`id` = `tasks`.`project` and `projects`.`status` = ?)
As you can see at the end of the raw query there's a question mark that wasn't replaced with the actual value, instead 'tasks'.'company' = 1 was.

You can listen to the illuminate.query event. Before the query add the following event listener:
use Event;
Event::listen('illuminate.query', function($query, $params, $time)
{
dd([
$query, // prepared statement
$params, // query params (? symbols will be replaced with)
$time // execution time
]);
});

I found a solution to this issue by manually setting the bindings using
->setBindings([Project::STATUS_ARCHIVED]);
Here's the whole snippet:
return $this->hasMany('App\Task', 'company')
->whereNotIn('id', function($query)
{
$query->from('tasks')->join('projects', function($join)
{
$join->on('projects.id', '=', 'tasks.project')
->where('projects.status', '=', '?');
})
->select('tasks.id')
->setBindings([Project::STATUS_ARCHIVED]);
})
->where('status', '=', Task::STATUS_INCOMPLETE);

You didn't add ->get(); to the end of the query.
Try:
return $this->hasMany('App\Task', 'company')
->whereNotIn('id', function($query)
{
$query->from('tasks')->join('projects', function($join)
{
$join->on('projects.id', '=', 'tasks.project')
->where('projects.status', '=', Project::STATUS_ARCHIVED);
})
->select('tasks.id');
})->get();

Related

Laravel query not giving desired result

Can someone help fix this query. Query is returning null result for "j.code" and "accounts.title". And I am 100% sure that it should return result. I think my left join are missing something. Is this the proper way of using left join within a left join.
$query = DB::table('autostk')
->where('autostk.branchid', $branch_id)
->where('autostk.itemcode',$request->itemcode)
->whereDate('autostk.date','<=',$request->tdate)
->leftjoin('journal AS j', function($join) use ($branch_id) {
$join->on('autostk.refno', '=', 'j.vno')
->where('j.code', '>=', 100)
->where('j.branchid', $branch_id)
->where('j.vtype', '=', 'autostk.vtype')
->leftjoin('accounts', 'j.code', '=', 'accounts.code')
->where('accounts.branchid', $branch_id);
})
->select('j.code','accounts.title','autostk.*')
->orderBY('date')->get()
->map(function ($item, $key) {
return (array) $item;
})
->all();
The raw query being generated is :
select `j`.`code`, `accounts`.`title`, `autostk`.* from `autostk`
left join (`journal` as `j` left join `accounts` on `j`.`code`=`accounts`.`code`)
on `autostk`.`refno` = `j`.`vno` and `j`.`code` >= ? and `j`.`branchid` = ?
and `j`.`vtype` = ? and `accounts`.`branchid` = ? where `autostk`.`branchid` = ?
and `autostk`.`itemcode` = ? and date(`autostk`.`date`) <= ? order by
`autostk`.`date` asc
UPDATE :
While checking the QueryLog i noticed that the binding for 'j'.'vtype' is "autostk.vtype"
Applying the query in workbench with 'autostk.vtype' returned null results.
But when I changed it to 'autostk'.'vtype' the results showed up correctly.
How to make this change in Laravel Eloquent ?
Please try like below:
$query = DB::table('autostk')
->where('autostk.branchid', $branch_id)
->where('autostk.itemcode',$request->itemcode)
->whereDate('autostk.date','<=',$request->tdate)
->leftjoin('journal as j', function($join) use ($branch_id) {
$join->on('autostk.refno', '=', 'j.vno')
->where('j.code', '>=', 100)
->where('j.branchid', $branch_id)
->where('j.vtype', '=', 'autostk.vtype')
->leftjoin('accounts', 'j.code', '=', 'accounts.code')
->where('accounts.branchid', $branch_id);
})
->select('j.code','accounts.title','autostk.*')
->orderBy('autostk.date')->get()
->map(function ($item, $key) {
return (array) $item;
})
->all();
There is one problem:
->orderBy('autostk.date')
And you can use toArray() instead of map() like this
->orderBy('autostk.date')->get()->toArray();
Found the solution. Correct query is :
$query = DB::table('autostk')
->where('autostk.branchid', $branch_id)
->where('autostk.itemcode',$request->itemcode)
->whereDate('autostk.date','<=',$request->tdate)
->leftjoin('journal AS j', function($join) use ($branch_id) {
$join->on('autostk.refno', '=', 'j.vno')
->on('autostk.vtype', '=', 'j.vtype')
->where('j.code', '>=', 100)
->where('j.branchid', $branch_id)
->leftjoin('accounts', 'j.code', '=', 'accounts.code')
->where('accounts.branchid', $branch_id);
})
->select('j.code','accounts.title','autostk.*')
->orderBY('autostk.date')->get()
->map(function ($item, $key) {
return (array) $item;
})
->all();
->leftjoin('journal as j', function($join) use ($branch_id) {
as instead of AS

Select unique records from child with condition on parent relationship

I have two tables, Shows and Episodes, each episode has show_id linking them one to many.
Now I need to get latest 6 episodes, one per show, where show.active is true
I've tried the following code:
$episodes = Episode::select(DB::raw('t.*'))
->from(DB::raw('(SELECT * FROM episodes ORDER BY id DESC) t'))
->whereHas('show', function($query) {
$query->where('active', '=', true);
})
->groupBy('t.show_id')
->take(6)
->get();
Unfortunately, I get the following:
Column not found: 1054 Unknown column 'episodes.show_id' in 'where clause' (SQL: select t.* from (SELECT * FROM episodes ORDER BY id DESC) t where exists (select * from shows where episodes.show_id = shows.id and active = 1) group by t.show_id limit 6)
I've also tried:
$episodes = Episode::where('active', true)
->orderBy('id', 'DESC')
->whereHas('show', function($query) {
$query->where('active', '=', true);
})
->groupBy('show_id')
->take(6)
->get();
It shows no error, but doesn't return latest of each show, groupBy gets the first record, I need the latest
This should work:
$episodes = Episode::where('active', true)
->whereHas('show', function($query) {
$query->where('active', '=', true);
})
->groupBy('show_id')
->orderBy('id', 'DESC')
->take(6)
->get();
You can try this
$episodes = Episode::selectRaw('max(id) as id, show_id')
->whereHas('show', function($query) {
$query->where('active', '=', true);
})
->orderBy('id', 'DESC')
->groupBy('show_id')
->take(6)
->get();
You can use a WHERE IN subquery:
$ids = Episode::selectRaw('max(id)')
->whereHas('show', function ($query) {
$query->where('active', '=', true);
})->groupBy('show_id');
$episodes = Episode::whereIn('id', $ids)
->take(6)
->get();

How to wrap Eloquent query with parenthesis when we use a conditional clauses in Laravel 5.7

I have a query that should load all the posts with just their english translation.
If the user enter a keyword it return just the english post with a title containing that keyword.
if ($searchKeywords||$searchCategory){
$posts = Post::
select('post_translations.post_id AS id', 'post_translations.title AS title', 'category_id', 'locale')
->join('post_translations', 'posts.id', '=', 'post_translations.post_id')
->where(‘post_translations.locale','=','en')
->when($searchKeywords, function ($query, $searchKeywords) {
return $query->where('post_translations.title', $searchKeywords)->orWhere('post_translations.title', 'like', '%' . $searchKeywords . '%');
})
->when($searchCategory, function ($query, $searchCategory) {
return $query->where('category_id', '=', $searchCategory);
->paginate(20);
}
else
$posts = Post::select('id', 'title', 'category_id')->orderBy('title')->paginate(20);
The generated query is this one:
SELECT `post_translations`.`post_id` AS `id`, `post_translations`.`title` AS `title`, `category_id`
FROM `posts` inner join `post_translations`
ON `posts`.`id` = `post_translations`.`post_id`
WHERE `post_translations`.`locale` = 'en'
AND `post_translations`.`title` = 'About'
OR `post_translations`.`title` like 'About’
LIMIT 20 OFFSET 0
That return me all the 3 posts translations of the post About.
This because of the orWhere.
How can I change the eloquent query in order to generate a query like this?
SELECT `post_translations`.`post_id` AS `id`, `post_translations`.`title` AS `title`, `category_id`
FROM `posts` inner join `post_translations`
ON `posts`.`id` = `post_translations`.`post_id`
WHERE `post_translations`.`locale` = 'en'
AND (`post_translations`.`title` = ‘About' OR `post_translations`.`title` like 'About’ )
LIMIT 20 OFFSET 0
The question is not a duplicate of this one because I have one more level of subquery.
How do you wrap Laravel Eloquent ORM query scopes in parentheses when chaining?
Add both condition inside a where query like this:
if ($searchKeywords) {
$posts = Post::select('post_translations.post_id AS id', 'post_translations.title AS title', 'category_id', 'locale')
->join('post_translations', 'posts.id', '=', 'post_translations.post_id')
->where(‘post_translations.locale','=','en')
->where(function ($query) use ($searchKeywords) {
$query->where('post_translations.title', $searchKeywords)
->orWhere('post_translations.title', 'like', '%' . $searchKeywords . '%');
})
->paginate(20);
}
I have solved with this code:
if ($searchKeywords||$searchCategory){
$posts = Post::
select('post_translations.post_id AS id', 'post_translations.title AS title', 'category_id', 'locale')
->join('post_translations', 'posts.id', '=', 'post_translations.post_id')
->when($searchKeywords, function ($query, $searchKeywords) {
return $query->where('post_translations.locale','=','en')
->where(function ($query) use ($searchKeywords) {
$query->where('post_translations.title', $searchKeywords)->orWhere('post_translations.title', 'like', '%' . $searchKeywords . '%');
});
})
->when($searchCategory, function ($query, $searchCategory) {
return $query->where('post_translations.locale','=','en')
->where(function ($query) use ($searchCategory) {
$query->where('category_id', '=', $searchCategory);
});
})
->paginate(20);
}
else
$posts = Post::select('id', 'title', 'category_id')->orderBy('title')->paginate(20);

Why query returns empty collection?

I have the following query was built by Laravel:
$res = Announcement::whereExists(function ($query) {
$query->select(DB::raw(1))
->from('announcement_category')->join('user_category', 'user_category.category_id', '=', 'announcement_category.category_id')
->where('user_category.user_id', '=', 1)
->where('announcement_category.announcement_id', '=', 'announcements.id');
});
dd($res->get());
The code above gives me empty collection: dd($res->get());.
The plain SQL code of this query is:
select * from `announcements` where exists (select 1 from
`announcement_category` inner join `user_category` on
`user_category`.`category_id` = `announcement_category`.`category_id` where `user_category`.`user_id` = 1
and `announcement_category`.`announcement_id` = announcements.id)
and `announcements`.`deleted_at` is null
If execute this directly in MySQL, I get two result rows.
But why dd($res->get()); retuns me empty?
I don't think there is a whereExists in eloquent model... try this:
$res = DB::table('announcement')->whereExists(function ($query) {
$query->select(DB::raw(1))
->from('announcement_category')->join('user_category', 'user_category.category_id', '=', 'announcement_category.category_id')
->where('user_category.user_id', '=', 1)
->where('announcement_category.announcement_id', '=', 'announcements.id');
})->get();

Laravel 5.2 : How to write query builder with 2 ON in this right join

I have this sql syntax
SELECT vehicles.license_plate, vehicles.year, vehicles.status, vehicles.zone_id, vehicles.car_class_id, harga_sewa.value, harga_sewa.description
FROM `vehicles`
RIGHT JOIN `harga_sewa` ON vehicles.zone_id = harga_sewa.zone_id
AND vehicles.car_class_id = harga_sewa.car_class_id
How I can write something like this?
DB::table('vehicles')
->rightJoin('harga_sewa', 'vehicles.zone_id', '=', 'harga_sewa.zone_id', AND vehicles.car_class_id = harga_sewa.car_class_id)
->select(*)
Try below code
DB::table('vehicles')
->rightJoin('harga_sewa', function ($join) {
$join->on('vehicles.zone_id', '=', 'harga_sewa.zone_id');
$join->on('vehicles.car_class_id', '=', 'harga_sewa.car_class_id');
})
->get();
On mobile, so can't test, but from memory this should work:
DB::table('vehicles')
->rightJoin('harga_sewa', 'vehicles.zone_id', '=', 'harga_sewa.zone_id')
->rightJoin('harga_sewa', 'vehicles.car_class_id', '=', 'harga_sewa.car_class_id')
->select('*')
->get();

Resources