Laravel query not giving desired result - laravel

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

Related

select from table (laravel) - where and orWhere

So, I'm using laravel and I want to make this query to work in laravel 'formula'
SELECT * FROM `complaints` WHERE (`fID` = 0) AND (`hide_topic` = 0 OR (`hide_topic` <= 0 OR (`hide_topic` > 3 AND byID = 52))) ORDER BY `status` ASC, `id` DESC
And I made something like this in laravel but not sure that selects correctly like the query above does.
DB::table('complaints')
->where('fID', '=', 0)
->where('hide_topic', '=', 0)
->orWhere('hide_topic', '<', 0)
->orWhere('hide_topic', '>', 3)
->where('byID', '=', 52)
->orderBy('status', 'asc')
->orderBy('id', 'desc')
->get();
Any help?
If you carefully examine your query. You can definitely remove some extra filters. If you see inner where if hide_topic <= 0 it also covers hide_topic =0 so you can reduce your query to.
SELECT *
FROM `complaints`
WHERE `fID` = 0
AND (`hide_topic` <= 0 OR (`hide_topic` > 3 AND byID = 52))
ORDER BY `status` ASC, `id` DESC
Best thing from laravel is that you can actually see the query that will be executed using query builders or eloquent model using toSql method. You can use toSql method at place of get, all or first functions.
$result = DB::table('complaints')
->where('fID', '=', 0)
->where(function($query) {
$query->where('hide_topic', '<=', 0)
->orWhere(function($query) {
$query->where('hide_topic', '>', 3)
->where('byID', '=', 52);
});
})
->orderBy('status', 'asc')
->orderBy('id', 'desc')
->get();
// to check the query just replace `->get();` to `->toSql();` in above query.
Now if you don't want any modifications in your existing query. You can reference to #OMR answer. Still I'll put it here.
$result = DB::table('complaints')
->where('fID', '=', 0)
->where(function($query) {
$query->where('hide_topic', '=', 0)
->orWhere(function($query) {
$query->where('hide_topic', '<=', 0)
->orWhere(function($query) {
$query->where('hide_topic', '>', 3)
->where('byID', '=', 52);
});
});
})
->orderBy('status', 'asc')
->orderBy('id', 'desc')
->get(); -- use toSql() to actually see the query before bindings.
you simply use where with clouser for every compound condition:
$admin_level=3;
$playerid=52;
DB::table('complaints')->where('fID', '=', 0)
->where(function ($query)use($admin_level,$playerid){
$query->where('hide_topic', '=', 0)->orWhere(function ($query)use($admin_level,$playerid){
$query->Where('hide_topic', '<', 0)->orWhere(function ($query)use($admin_level,$playerid){
$query ->Where('hide_topic', '>', $admin_level)
->where('byID', '=', $playerid);
});
});
})
->orderBy('status', 'asc')
->orderBy('id', 'desc')
->get();

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

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 query builder not replacing question mark

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

A JOIN With Additional Conditions Using Query Builder or Eloquent

I'm trying to add a condition using a JOIN query with Laravel Query Builder.
<?php
$results = DB::select('
SELECT DISTINCT
*
FROM
rooms
LEFT JOIN bookings
ON rooms.id = bookings.room_type_id
AND ( bookings.arrival between ? and ?
OR bookings.departure between ? and ? )
WHERE
bookings.room_type_id IS NULL
LIMIT 20',
array('2012-05-01', '2012-05-10', '2012-05-01', '2012-05-10')
);
I know I can use Raw Expressions but then there will be SQL injection points. I've tried the following with Query Builder but the generated query (and obviously, query results) aren't what I intended:
$results = DB::table('rooms')
->distinct()
->leftJoin('bookings', function ($join) {
$join->on('rooms.id', '=', 'bookings.room_type_id');
})
->whereBetween('arrival', array('2012-05-01', '2012-05-10'))
->whereBetween('departure', array('2012-05-01', '2012-05-10'))
->where('bookings.room_type_id', '=', null)
->get();
This is the generated query by Laravel:
select distinct * from `room_type_info`
left join `bookings`
on `room_type_info`.`id` = `bookings`.`room_type_id`
where `arrival` between ? and ?
and `departure` between ? and ?
and `bookings`.`room_type_id` is null
As you can see, the query output doesn't have the structure (especially under JOIN scope). Is it possible to add additional conditions under the JOIN?
How can I build the same query using Laravel's Query Builder (if possible) Is it better to use Eloquent, or should stay with DB::select?
$results = DB::table('rooms')
->distinct()
->leftJoin('bookings', function($join)
{
$join->on('rooms.id', '=', 'bookings.room_type_id');
$join->on('arrival','>=',DB::raw("'2012-05-01'"));
$join->on('arrival','<=',DB::raw("'2012-05-10'"));
$join->on('departure','>=',DB::raw("'2012-05-01'"));
$join->on('departure','<=',DB::raw("'2012-05-10'"));
})
->where('bookings.room_type_id', '=', NULL)
->get();
Not quite sure if the between clause can be added to the join in laravel.
Notes:
DB::raw() instructs Laravel not to put back quotes.
By passing a closure to join methods you can add more join conditions to it, on() will add AND condition and orOn() will add OR condition.
If you have some params, you can do this.
$results = DB::table('rooms')
->distinct()
->leftJoin('bookings', function($join) use ($param1, $param2)
{
$join->on('rooms.id', '=', 'bookings.room_type_id');
$join->on('arrival','=',DB::raw("'".$param1."'"));
$join->on('arrival','=',DB::raw("'".$param2."'"));
})
->where('bookings.room_type_id', '=', NULL)
->get();
and then return your query
return $results;
You can replicate those brackets in the left join:
LEFT JOIN bookings
ON rooms.id = bookings.room_type_id
AND ( bookings.arrival between ? and ?
OR bookings.departure between ? and ? )
is
->leftJoin('bookings', function($join){
$join->on('rooms.id', '=', 'bookings.room_type_id');
$join->on(DB::raw('( bookings.arrival between ? and ? OR bookings.departure between ? and ? )'), DB::raw(''), DB::raw(''));
})
You'll then have to set the bindings later using "setBindings" as described in this SO post:
How to bind parameters to a raw DB query in Laravel that's used on a model?
It's not pretty but it works.
The sql query sample like this
LEFT JOIN bookings
ON rooms.id = bookings.room_type_id
AND (bookings.arrival = ?
OR bookings.departure = ?)
Laravel join with multiple conditions
->leftJoin('bookings', function($join) use ($param1, $param2) {
$join->on('rooms.id', '=', 'bookings.room_type_id');
$join->on(function($query) use ($param1, $param2) {
$query->on('bookings.arrival', '=', $param1);
$query->orOn('departure', '=',$param2);
});
})
I am using laravel5.2 and we can add joins with different options, you can modify as per your requirement.
Option 1:
DB::table('users')
->join('contacts', function ($join) {
$join->on('users.id', '=', 'contacts.user_id')->orOn(...);//you add more joins here
})// and you add more joins here
->get();
Option 2:
$users = DB::table('users')
->join('contacts', 'users.id', '=', 'contacts.user_id')
->join('orders', 'users.id', '=', 'orders.user_id')// you may add more joins
->select('users.*', 'contacts.phone', 'orders.price')
->get();
option 3:
$users = DB::table('users')
->leftJoin('posts', 'users.id', '=', 'posts.user_id')
->leftJoin('...', '...', '...', '...')// you may add more joins
->get();
For conditional params we can use where,
$results = DB::table('rooms')
->distinct()
->leftJoin('bookings', function($join) use ($param)
{
$join->on('rooms.id', '=', 'bookings.room_type_id')
->where('arrival','=', $param);
})
->where('bookings.room_type_id', '=', NULL)
->get();
There's a difference between the raw queries and standard selects (between the DB::raw and DB::select methods).
You can do what you want using a DB::select and simply dropping in the ? placeholder much like you do with prepared statements (it's actually what it's doing).
A small example:
$results = DB::select('SELECT * FROM user WHERE username=?', ['jason']);
The second parameter is an array of values that will be used to replace the placeholders in the query from left to right.
My five cents for scheme LEFT JOIN ON (.. or ..) and (.. or ..) and ..
->join('checks','checks.id','check_id')
->leftJoin('schema_risks', function (JoinClause $join) use($order_type_id, $check_group_id, $filial_id){
$join->on(function($join){
$join->on('schema_risks.check_method_id','=', 'check_id')
->orWhereNull('schema_risks.check_method_id')
;
})
->on(function($join) use ($order_type_id) {
$join->where('schema_risks.order_type_id', $order_type_id)
->orWhereNull('schema_risks.order_type_id')
;
})
->on(function($join) use ($check_group_id) {
$join->where('schema_risks.check_group_id', $check_group_id)
->orWhereNull('schema_risks.check_group_id')
;
})
->on(function($join) use($filial_id){
$join->whereNull('schema_risks.filial_id');
if ($filial_id){
$join->orWhere('schema_risks.filial_id', $filial_id);
}
})
->on(function($join){
$join->whereNull('schema_risks.check_risk_level_id')
->orWhere('schema_risks.check_risk_level_id', '>' , CheckRiskLevel::CRL_NORMALLLY );
})
;
})

Resources