laravel 5.1 eloquent query - php

I got a query that works fine in PMA and I'm trying to convert it to Eloquent, but I must be missing something.
Here the SQL query:
SELECT t1.* FROM ppr__child_absence t1
LEFT JOIN ppr__children t3 ON t3.idcode=t1.child_idcode
WHERE t1.id = (SELECT t2.id FROM ppr__child_absence t2
WHERE t2.child_idcode = t1.child_idcode
ORDER BY t2.id DESC LIMIT 1)
AND t3.deleted_at IS NULL
AND $input BETWEEN start AND stop;
and hes is my eloquent query:
$input = Request::all();
$pprs =
DB::table('ppr__child_absence')
->join('ppr__children', function($join) {
$join->on('ppr__children.idcode', '=', 'ppr_children_absence.child_idcode')
->where('ppr__child_absence.child_idcode', '=', DB::raw('SELECT t2.id FROM ppr__child_absence t2
WHERE t2.child_idcode = ppr__child_absence.child_idcode
ORDER BY t2.id DESC LIMIT 1'));})
->whereNull('ppr__children.deleted_at')
->whereBetween($input, array('ppr_children_absence.start','ppr_children_absence.stop'))->get();
I'm keep getting error:
ErrorException in Grammar.php line 58:
strtolower() expects parameter 1 to be string, array given.
Can anyone here lead me to right direction?
Basically user has 1 date input with datepicker and submit button to get result according to the date chosen.
working query here with out errors but no results
$input = Request::all();
$pprs = DB::table('ppr__child_absence')
->select('ppr__child_absence.*')
->join('ppr__children', function($join) {
$join->on('ppr__children.idcode', '=', 'ppr__child_absence.child_idcode')
->where('ppr__child_absence.id', '=', DB::raw('SELECT t2.id FROM ppr__child_absence t2
WHERE t2.child_idcode = ppr__child_absence.child_idcode
ORDER BY t2.id DESC LIMIT 1'));})
->whereNull('ppr__children.deleted_at')
->where('ppr__child_absence.start', '<', $input['ppr_day'])
->where('ppr__child_absence.stop', '>', $input['ppr_day'])->get();

$input = Request::all(); stores all the input fields in an array.
You are using ->whereBetween($input,...) and the first parameter of whereBetween() is expected to be a string (the name of the table column) but you are passing an array.
You didn't give details about the input. Assuming the input contains a field called 'field', the you should use ->whereBetween($input['field'],...) instead

What you seem to want is not what the whereBetween method offers. When using whereBetween the logic is that you want a given column value to be between two input values. The example in the Laravel Query Builder Documentation is chosen well:
// the column 'votes' value should be between 1 and 100
$users = DB::table('users')->whereBetween('votes', [1, 100]);
What you seem to want is to make sure an input value is between two different column values. You can do that by having two separate conditions:
->where('ppr_children_absence.start', '<', $input['value'])
->where('ppr_children_absence.stop', '>', $input['value'])
This will make sure that $input['value']) is between the start and stop column values.

Related

laravel access outer query column inside subquery

I am trying to convert raw sql queries into laravel queries.
Here's the raw query:
select
tsk.id,
tsk.request_id,
tsk.sys_index,
tsk.category_group,
tsk.category,
tsk.is_assigned,
tsk.hash_id
from
user_tasks as usr
inner join
unassigned_tasks as tsk
on usr.task_id = tsk.id
where
usr.assigned_to = 12
AND
tsk.product_id NOT IN ( SELECT product_id FROM product_progresses WHERE request_id = tsk.request_id )
AND
BINARY hash_id NOT IN ( SELECT hash_id FROM product_match_unmatches WHERE request_id = tsk.request_id AND auto_unmatched_by IS NOT NULL )
The laravel query is:
public function getTasks($assigned_to) {
/** fetch products assigned to a specific user token,
* ignore already matched skus, and links that are auto-unmatched
**/
$tasks = DB::table('user_tasks as usr')
->join('unassigned_tasks as tsk', 'usr.task_id', '=', 'tsk.id')
->select('tsk.id', 'tsk.request_id', 'tsk.sys_index', 'tsk.category_group', 'tsk.category', 'tsk.is_assigned', 'tsk.hash_id')
->where('usr.assigned_to', '=', $assigned_to);
$tasks->whereNotIn('tsk.product_id', function($qs) {
$qs->from('product_progresses')
->select(['product_id'])
->where('request_id', '=', 'tsk.request_id')
->get();
});
$tasks->whereNotIn(DB::raw('BINARY `hash_id`'), function($qs) {
$qs->from('product_match_unmatches')
->select('hash_id')
->where('request_id', '=', 'tsk.request_id')
->whereNotNull('auto_unmatched_by')
->get();
});
return $tasks->toSql();
The below query should take tsk.request_id value from outer query, but I think the column value is not passed to it.
Here's the output of toSql():
SELECT `tsk`.`id`,
`tsk`.`request_id`,
`tsk`.`sys_index`,
`tsk`.`category_group`,
`tsk`.`category`,
`tsk`.`is_assigned`,
`tsk`.`hash_id`
FROM `user_tasks` AS `usr`
INNER JOIN `unassigned_tasks` AS `tsk`
ON `usr`.`task_id` = `tsk`.`id`
WHERE `usr`.`assigned_to` = ?
AND `tsk`.`product_id` NOT IN (SELECT `product_id`
FROM `product_progresses`
WHERE `request_id` = ?)
AND BINARY `hash_id` NOT IN (SELECT `hash_id`
FROM `product_match_unmatches`
WHERE `request_id` = ?
AND `auto_unmatched_by` IS NOT NULL)
Note the ? inside where clauses.
The resultset is different from the raw and laravel query.
I even tried see the bindings value:
//dd($tasks->getBindings());
$sql = str_replace_array('?', $tasks->getBindings(), $tasks->toSql());
dd($sql);
And on running this raw query, it is outputting the correct result-set.
UPDATE:
On checking the bindings, here's what I found:
array:3 [▼
0 => 12
1 => "tsk.request_id"
2 => "tsk.request_id"
]
Here outer query column is wrapped inside quotes and hence treated as a string.
So maybe where clause is trying to compare request_id with a string rather than the outer column.
If it is so, then how do I make them treat as columns rather than string?
use DB::raw() where you trying to add value of request_id
Example
AND `tsk`.`product_id` NOT IN (SELECT `product_id`
FROM `product_progresses`
WHERE `request_id` = DB::raw('tsk.request_id'))
whereRaw('pgr.request_id = tsk.request_id');
Solved the string issue.
You should try to remove select() method, in the subquery replace where() method with whereColumn() method and remove get() method:
$tasks = DB::table('user_tasks', 'urs')
->join('unassigned_tasks as tsk', 'usr.task_id', '=', 'tsk.id')
->where('usr.assigned_to', '=', $assigned_to);
Note: i put the alias 'urs' as second argument (view docs)
$tasks->whereNotIn('tsk.product_id', function($qs) {
$qs->from('product_progresses')
->select(['product_id'])
->whereColumn('request_id', 'tsk.request_id');
});
If you want get specific fields, you must specify the fields in get() method:
return $tasks->get(array('tsk.id', 'tsk.request_id', 'tsk.sys_index', 'tsk.category_group', 'tsk.category', 'tsk.is_assigned', 'tsk.hash_id'));

How to use multiple condition in leftjoin with raw query in laravel5

I need to join two table to fetch data with multiple condition on leftjoin but
i am getting this error. Not enough arguments for the on clause I am using laravel5.2. How to use raw query with leftjoin multiple condition.
$activityDetail = DB::table('table1 as UA')
->selectRaw('SUM(UA.total_calory) as total_calory,
SUM(UA.flight_descend) as flight_descend,date('.$tz_start_date.') as start_date')
->leftjoin('table2 as LC',function($join) use($tz_lccreated_date,$dateRange){
$join->on('LC.user_id_fk','=','UA.user_id_fk');
$join->on('LC.is_active','=',DB::raw('1'));
$join->on(' date('.DB::raw($tz_lccreated_date).') '.DB::raw($dateRange));
})
->whereRaw(' date('.$tz_start_date.') '.$dateRange)
->where('UA.user_id_fk','=',base64_decode($params['uid']))
->groupBy(DB::raw('date('.$tz_start_date.')'))
->get();
Raw query is
select SUM(UA.total_calory) as total_calory,
SUM(UA.flight_descend) as flight_descend,
date(CONVERT_TZ(UA.start_date,"+00:00","+05:30")) as start_date
from `table1` as `UA`
left join `table2` as `LC`
on `LC`.`user_id_fk` = `UA`.`user_id_fk` and `LC`.`is_active` = 1
and `date(CONVERT_TZ(LC`.`created_date,"+00:00","+05:30"))` = `current_date`
where date(CONVERT_TZ(UA.start_date,"+00:00","+05:30")) = current_date
and `UA`.`user_id_fk` = 411
group by date(CONVERT_TZ(UA.start_date,"+00:00","+05:30"))
I have resolved my problem, after a lots of analysis, i am not getting any kind of solution of raw query in join clause then i am using subquery and resolve my problem.
$mannualLoggedQuery = 'IFNULL((select sum(calory) as cal from table2 as LC where LC.user_id_fk = "'.base64_decode($params['uid']).'" and date('.$tz_lccreated_date.')'.$dateRange.'),0)';
$activityDetail = DB::table('table1 as UA')->selectRaw('SUM(UA.total_calory) + '.$mannualLoggedQuery.' as total_calory,
date('.$tz_start_date.') as start_date')
->where('UA.user_id_fk','=',base64_decode($params['uid']))
->whereRaw('date('.$tz_start_date.') '.$dateRange)
->groupBy(DB::raw('date('.$tz_start_date.')'))
->get();

Laravel query with max and group by

I need to create a select query in Laravel 5.1 which I will have no problems creating via regular SQL and I am wondering if you could help me to write it in Laravel.
I created this query that gets all Users that have a truck, trailer and delivery_date equals a particular date (comes from $week_array). It is working, but it is missing some components
$RS = $this->instance->user()
->with(['driver.delivery' => function($query) use ($week_array) {
$query->where('delivery_date', [Carbon\Carbon::parse($week_array['date'])->toDateTimeString()]);
}])
->with(['driver.trailer', 'driver.truck', 'driver.trailer.trailerType'])->get();
I need to exclude those drivers that have MAX delivery date which equals or greater than selected delivery date in the query above. This is the normal query that I need to plug-in to laravel.
In other words, I need to convert the following query (simplified) to Laravel:
SELECT
*
FROM
USERS
INNER JOIN
DRIVERS ON DRIVERS.user_id = USERS.id
INNER JOIN
DELIVERIES ON DELIVERIES.driver_id = DRIVERS.id
WHERE
1 = 1
AND DELIVERIES.driver_id NOT IN (SELECT
driver_id
FROM
DELIVERIES
GROUP BY driver_id
HAVING MAX(delivery_date) >= '2016-05-10')
You're looking for whereHas. Try:
$date = Carbon\Carbon::parse($week_array['date'])->toDateTimeString();
$RS = $this->instance->user()
->with(['driver.delivery' => function($query) use ($date) {
$query->where('delivery_date', [$date]);
}])
->with(['driver.trailer', 'driver.truck', 'driver.trailer.trailerType'])
->whereHas('driver.delivery', function($query) use ($date) {
return $query->where('delivery_date', '>', $date);
}, '=', 0)
->get();
Also try validating the query looks right by replacing ->get() with ->toSql() and using the dd helper function.

SQL exists in Laravel 5 query builder

Good morning,
I've been trying for quite a lot of time to translate this query(which returns an array of stdClass) into query builder so I could get objects back as Eloquent models.
This is how the query looks like untranslated:
$anketa = DB::select( DB::raw("SELECT *
FROM v_anketa a
WHERE not exists (select 1 from user_poeni where anketa_id=a.id and user_id = :lv_id_user)
Order by redni_broj limit 1"
), array( 'lv_id_user' => $id_user,
));
I have tried this, but it gives a syntax error near the inner from in the subquery:
$anketa = V_anketa::selectRaw("WHERE not exists (select 1 from user_poeni where anketa_id=a.id and user_id = :lv_id_user)", array('lv_id_user' => $id_user,)
)->orderBy('redni_broj')->take(1)->first();
The problem is this exists and a subquery in it. I couldn't find anything regarding this special case.
Assume each table has an appropriate Eloquent model.
V_anketa is a view. The db is postgresql.
As far as the query goes I believe this should work:
$anketa = V_anketa::whereNotExists(function ($query) use ($id_user) {
$query->select(DB::raw(1))
->from('user_poeni')
->where('anketa.id', '=', 'a.id')
->where('user_id', '=', $id_user);
})
->orderBy('redni_broj')
->first();
but I'm not clear on what do you mean by "assuming every table has an Eloquent model" and "V_anketa" is a view...
Assuming the SQL query is correct, this should work:
$anketa = DB::select(sprintf('SELECT * FROM v_anketa a WHERE NOT EXISTS (SELECT 1 FROM user_poeni WHERE anketa_id = a.id AND user_id = %s) ORDER BY redni_broj LIMIT 1', $id_user));
If you want to get back an Builder instance you need to specify the table:
$anketa = DB::table('')->select('');
If you however, want to get an Eloquent Model instance, for example to use relations, you need to use Eloquent.

Left join to get a single row in Laravel

I have been unsuccessfully trying to leftjoin and get the required data
Here is my code:
$album = Albums::->where('users_id',$user_id)
->leftJoin('photos',function($query){
$query->on('photos.albums_id','=','albums.id');
$query->where('photos.status','=',1);
//$query->limit(1);
//$query->min('photos.created_at');
})
->where('albums.status',1)->get();
The comments are some of my several trying...
I want to get only a single record from the photos table matching the foreign key album_id which was updated first and also with status 1
pls help...
I have used DB::raw() in order to achieve this
$album = Albums::select( 'albums.*',
DB::raw('(select photo from photos where albums_id = albums.id and status = 1 order by id asc limit 1) as photo') )
->where('users_id',$user_id)
->where('albums.status',1)->get();
#JarekTkaczyk 's coding was similar and displayed the same result as I needed, so a special thanks to him for his time and effort...
But comparing the execution time for the quires I stayed to mine as my above snippet
select `albums`.*, (select photo from photos where albums_id = albums.id and status = 1 order by id asc limit 1) as photo from `albums` where `users_id` = '1' and `albums`.`status` = '1'
took 520μs - 580μs
and #JarekTkaczyk 's
select `albums`.*, `p`.`photo` from `albums` left join `photos` as `p` on `p`.`albums_id` = `albums`.`id` and `p`.`created_at` = (select min(created_at) from photos where albums_id = p.albums_id) and `p`.`status` = '1' where `users_id` = '1' and `albums`.`status` = '1' group by `albums`.`id`
took 640μs - 750μs But both did the same...
You can achieve it using either leftJoin or rightJoin (but the latter would return Photo models, so probably you won't need that):
Albums::where('users_id', $user_id)
->leftJoin('photos as p', function ($q) {
$q->on('photos.albums_id', '=', 'albums.id')
->on('photos.updated_at', '=',
DB::raw('(select min(updated_at) from photos where albums_id = p.albums_id)'))
->where('photos.status', '=', 1);
})
->where('albums.status', 1)
->groupBy('albums.id')
->select('albums.*', fields from photos table that you need )
->get();
Are you trying to check for albums that have the status of '1'? If this is the case you are missing an equals sign from your final where.
Try:
->where('albums.status','=',1)->first();
Alternatively you may be able to achieve this with an 'on' instead of a 'where' inside the join function. You also don't need to split up query inside of the function and can do it as one line with the '->' :
$album = Albums::->where('users_id',$user_id)
->leftJoin('photos',function($query){
$query->on('photos.albums_id','=','albums.id')
->on('photos.status','=',1);
})
->where('albums.status','=',1)->first();
You need to make sure that you are using 'first', as it will return a single row of the first result. Get() will return an array.
As a straightforward answer which results in a single object I suggest the following query:
$album = DB::table('albums')->select('albums.*', 'photos.photo')
->join('photos', 'photos.id', '=', 'albums.id')
->where('users_id',$user_id)
->where('albums.status',1)
->first();

Categories