Laravel 5.4 subquery in where condition? - php

I want to write sub query inside where in condition and in subquery were condition, checking with parent query field.
as follows,
$query = DB::table('users');
$query->whereNotIn('users.id', function($query) use ($request) {
$query->select('award_user.user_id')
->from('award_user')
->where('award_user.user_id', 'users.id')
->where('award_user.award_id', $request->award_id);
});
Query is working fine, but
->where('award_user.user_id', 'users.id')
This line, users.id is not taking from parent query. If I enter manually number, then it is working correctly.
What is wrong with my query.. can you please suggest.

use whereRaw rather than where
$query = DB::table('users');
$query->whereNotIn('users.id', function($query) use ($request) {
$query->select('award_user.user_id')
->from('award_user')
->whereRaw('award_user.user_id', 'users.id')
->whereRaw('award_user.award_id = '.$request->award_id);
});

Related

Laravel and PHP - Condition in the SQL request

I have a query
$BaseUsers = DB::table('users', 'users.ustatus', '=', '1')
->join('user_infos', 'user_infos.user_id', '=', 'users.id')
->select('users.*', 'user_infos.add1', 'user_infos.add3')
->paginate(3);
It work fine. But i need insert condition "where" to search in result
i send $request from form. How insert condition to query?
In PHP it looks like this:
if($request['add_1'])
{
$insert1=" and add_1<>'' ";
}
if($request['add_2'])
{
$insert2=" and add_2<>'' ";
}
...
$sql=" SELECT users.*, user_infos.add1, user_infos.add3 FROM users JOIN user_infos where users.ustatus=1 and user_infos.user_id=users.id ".$insert1." ".$insert2."";
How can this be done on laravel in Controller? I mean - just insert the necessary condition insert1, insert2 ... into the query
you can use where() and has() to build your query
$query = DB::table('users');
if($request->has('age')) {
$query->where('age', '>', $request->age);
}
$query = $query->get();
I hope it's helpful
All is simple ) I use when in query
$BaseUsers = DB::table('users', 'users.ustatus', '=', '1')
->join('user_infos', 'user_infos.user_id', '=', 'users.id')
->when($request->input('f_add3'), function ($query) {
return $query->where('user_infos.add3', '<>', '');
})
->select('users.*', 'user_infos.add1', 'user_infos.add3')
->paginate(3);

Get last record on GROUP BY using Laravel & MySql

I have two table (users and messages) .. I wrote a query to get all messages that users sent to me or I sent, using JOIN .. to get all the users I have contacted or they did.
as in the code below:
$users = Message::join('users', function ($join) {
$join->on('messages.sender_id', '=', 'users.id')
->orOn('messages.receiver_id', '=', 'users.id');
})
->where(function ($q) {
$q->where('messages.sender_id', Auth::user()->id)
->orWhere('messages.receiver_id', Auth::user()->id);
})
->orderBy('messages.created', 'desc')
->groupBy('users.id')
->paginate();
The problem here is when records grouped, I'm getting the old message not the new one according to its created_at .. So, I want to get the last record of the grouped records.
It seems like it would make more sense to make use of Eloquent's relationships here so that you can eager load the relationships instead of having to use join and group by:
$messages = Message::with('sender', 'receiver')
->where(function ($query) {
$query->where('sender_id', auth()->id())
->orWhere('receiver_id', auth()->id())
})
->orderByDesc('created') // is this meant to be 'created_at'?
->paginate();

Using subqueries in Eloquent/Laravel

Here's the query in raw SQL:
SELECT *
FROM (
SELECT `characters`.`id`,`characters`.`refreshToken`,
`characters`.`name`,max(`balances`.`created_at`) as `refreshDate`
FROM `characters`
INNER JOIN `balances` ON `characters`.`id` = `balances`.`character`
WHERE `characters`.`refreshToken` IS NOT NULL
GROUP BY `characters`.`id`
) AS `t1`
WHERE `refreshDate` < '2017-03-29';
I've tested this in phpMyAdmin and it returns the expected results. However I'm using the Eloquent and Laravel libraries in my PHP app and I'm not sure how to approach this. How exactly do subqueries work in this case?
You can do a subquery as a table but need to create the subquery first and then merge the bindings into the parent query:
$sub = Character::select('id', 'refreshToken', 'name')
->selectSub('MAX(`balances`.`created_at`)', 'refreshDate')
->join('balances', 'characters.id', '=', 'balances.character')
->whereNotNull('characters.refreshToken')
->groupBy('characters.id');
DB::table(DB::raw("($sub->toSql()) as t1"))
->mergeBindings($sub)
->where('refreshDate', '<', '2017-03-29')
->get();
If that is your entire query you can do it without the subquery and use having() instead like:
Character::select('id', 'refreshToken', 'name')
->selectSub('MAX(`balances`.`created_at`)', 'refreshDate')
->join('balances', 'characters.id', '=', 'balances.character')
->whereNotNull('characters.refreshToken')
->groupBy('characters.id')
->having('refreshDate', '<', '2017-03-29');
You can use subqueries in Eloquent by specifying them as a closure to the where method. For example:
$characters = Character::where(function ($query) {
// subqueries goes here
$query->where(...
...
->groupBy('id');
})
->where('refreshDate', '<', '2017-03-29')
->get();
You have to chain your methods to the $query variable that is passed to the closure in the above example.
If you want to pass any variable to the subquery you need the use keyword as:
$characterName = 'Gandalf';
$characters = Character::where(function ($query) use ($characterName) {
// subqueries goes here
$query->where('name', $characterName)
...
->groupBy('id');
})
->where('refreshDate', '<', '2017-03-29')
->get();

laravel belongsToMany Filter

I have three tables as below:
users
id|name|username|password
roles
id|name
users_roles
id|user_id|role_id
These tables communicate via belongsToMany.
I would like to find a way to select all data in “users” table except ones that their user value of "role_id" is 5 in table “users_roles”.
How can I do it?
You should use whereDoesntHave() to select models that don't have a related model meeting certain criteria:
$users = User::whereDoesntHave('roles', function($q){
$q->where('role_id', 5);
})->get();
Use Laravel's Query Builder:
<?php
$users = DB::table('users')
->leftJoin('users_roles', 'user.id', '=', 'users_roles.user_id')
->where('users_roles.role_id', '!=', 5)
->get();
http://laravel.com/docs/4.2/queries
Or using Eloquent directly:
<?php
$users = User::whereHas('users_roles', function($q)
{
$q->where('role_id', '!=', 5);
})->get();
http://laravel.com/docs/4.2/eloquent#querying-relations
<?php
$users = User::whereHas('roles', function($query) {
$query->where('id', '<>', 5);
})
->orHas('roles','<', 1)
->get();
I think the correct answer is:
User::whereHas('roles', function ($query) {
$query->whereId(5)
}, '=', 0)->get();
This code should send a query that checks if the role with id=5 is related to the user or not.
Edit
While I think this should work but the #lukasgeiter answer is preferable.
In the end both methods use the has() to count the related models by using a subquery in the db query where clause but when you use the whereDoesntHave() it specifies the operator < and the count 1 itself.
You can var_dump(DB::getQueryLog()) in App::after()'s callback to see the actual query.

Eloquent - join clause with string value rather than column heading

I have a question regarding join clauses in Eloquent, and whether you can join on a string value rather than a table column.
I have the code below querying a nested set joining parent/child records in a table 'destinations' via a table 'taxonomy'.
The second $join statement in the closure is the one causing an issue; Eloquent assumes this is a column, when I would actually just like to join on t1.parent_type = 'Destination' - ie, t1.parent_type should = a string value, Destination.
$result = DB::connection()
->table('destinations AS d1')
->select(array('d1.title AS level1', 'd2.title AS level2'))
->leftJoin('taxonomy AS t1', function($join) {
$join->on('t1.parent_id', '=', 'd1.id');
$join->on('t1.parent_type', '=', 'Destination');
})
->leftJoin('destinations AS d2', 'd2.id', '=', 't1.child_id')
->where('d1.slug', '=', $slug)
->get();
Is it possible to force Eloquent to do this? I've tried replacing 'Destination' with DB::raw('Destination') but this does not work either.
Thanking you kindly.
Another best way to achieve same is :
$result = DB::connection()
->table('destinations AS d1')
->select(array('d1.title AS level1', 'd2.title AS level2'))
->leftJoin('taxonomy AS t1', function($join) {
$join->on('t1.parent_id', '=', 'd1.id');
$join->where('t1.parent_type', '=', 'Destination');
})
->leftJoin('destinations AS d2', 'd2.id', '=', 't1.child_id')
->where('d1.slug', '=', $slug)
->get();
Replace your on with where
try using DB::raw("'Destination'")

Categories