how to union and groupby in laravel - laravel

i want to get contact id who was send chat or was i send chat to him
with native query i can get result but when i implement in laravel its going difficult
this my native query
select * from `users` where `users`.`id` in (
select `to` from messages where `from` = 2 group by `to`
union
select `from` from messages where `to` = 2 group by `from`
)
what i find difficult is how union after group by or group by after union with make same column number, i using merge but the result is wrong
this what i have try in laravel
$to = Message::select('to')->where('from',auth()->id())->groupBy('to')->get();
$from = Message::select('from')->where('to',auth()->id())->groupBy('from')->get();
$tofrom = $to->merge($from);
dd($tofrom);
please if any body can help

Unions are described in the documentation. To achieve your specific requirements you can do:
$final = User::whereIn('id', function ($query) {
$from = Message::select('from')->where('from',auth()->id())->groupBy('from');
$query->from('messages')->where('to',auth()->id())->groupBy('to')->union($from);
})->get();
Disclaimer: I have not actually tested this but I think it should work.

merge() is the method of collection. Not the Eloquent Builder or Query Builder.
However, It think you want to find user.id in the array.
You can convert the collection to array:
$to = Message::where('from',auth()->id())->groupBy('to')->pluck('to');
$from = Message::where('to',auth()->id())->groupBy('from')->pluck('from');
$tofrom = $to->merge($from)->toarray();
User::whereIn('id', $tofrom)->get();

oh finally i got the answer this is code
$contacts = User::select('users.id','users.name','users.email','users.profile_image')
->join('messages',function($join){
$join->on('users.id','messages.from');
$join->orOn('users.id','messages.to');
})
->where(function($query){
$query->where('messages.from',auth()->id())->orWhere('messages.to',auth()->id());
})
->groupBy('users.id','users.name','users.email','users.profile_image')
->get();

Related

Laravel 8 - How I do where clause in table added with join

Hi I want to know how can i do this query in Laravel 8 , I tried adding the join clause but not work as expected, i need join clause? Or maybe there is another form to do it. I search others examples but i don´t see anythat help me. The query is the next:
DB::table('escandallo_p as esc')
->select("esc.material", "esc.referencia", "esc.ancho", "esc.proveedor", "esc.punto",
"esc.precio", "esc.consumo", "esc.veces", "esc.001", "esc.002", "esc.003", "esc.004",
"esc.005", "esc.006", "esc.007", "esc.008", "esc.009", "esc.010", "esc.011", "esc.um", "esc.merma", "esc.importe", "esc.tipo", "esc.xtalla", "esc.fase",
DB::raw("(select anulado from prototipos_p as p where p.prototipo = '".$scandal[0]->prototipo."' and p.tipo = 'c' and p.referencia = esc.referencia )"),
// ignore
//original query "(select anulado from prototipos_p as p where p.prototipo = ",$request->prototipo," and p.tipo = 'c' and p.referencia = esc.referencia ) as 'anulado'",
// "(select clase from prototipos_p as p where p.prototipo = ",$request->prototipo," and p.tipo = 'c' and p.referencia = esc.referencia ) as 'clase'")
//Converted query ->select('pro.anulado')->where('pro.prototipo', $request->prototipo)
// ->where("p.prototipo", "=", $request->prototipo)
->where("esc.id_escandallo", "=", $request->id_escandallo)
->where("esc.id_version", "=", $request->version)
->orderBy("id","asc")
->get();
!!!! I need to pass the esc.referencia to the sub select query
The second select is the conversion of the select inside "" ( i know this is wrong is only for explain it).
Thank you in advance for any suggestion.
Best regards
EDIT: I can solve my problem with DB::raw, but if anyone know others methos are welcome!
You need to pass callback to the join query to add the extra query to the laravel's join method,
Example from Laravel Doc:
DB::table('users')
->join('contacts', function ($join) {
$join->on('users.id', '=', 'contacts.user_id')
->where('contacts.user_id', '>', 5);
})
->get();
It is explained in Laravel's doc, Advanced Join Clauses
There is Subquery support too Subquery Joins,
Eg:
$latestPosts = DB::table('posts')
->select('user_id', DB::raw('MAX(created_at) as last_post_created_at'))
->where('is_published', true)
->groupBy('user_id');
$users = DB::table('users')
->joinSub($latestPosts, 'latest_posts', function ($join) {
$join->on('users.id', '=', 'latest_posts.user_id');
})
->get();
These two might help you to achieve what you are trying
After test joins, joinSub, whereIn and other forms of doing this, I solved my problem using the DB::raw():
DB::table('escandallo_p as esc')
->select('parameters',....,
DB::raw("(SELECT column //(ONLY ONE)
FROM table
WHERE column = '".$parameter."' ...) AS nombre"),
)
->where('column', "=", $parameter)
->orderBy("id","asc")
->get();

db::raw adding is null in query

I am trying to use laravel query builder like:-
$users = DB::table('baid_collection')
->select(DB::raw('sum(total) as total_collect,collection_limit_c'))
->join('users_cstm', 'baid_collections.assigned_user_id', '=', 'users_cstm.id_c')
->where(DB::raw("assigned_user_id = '$userId' and DATE(date_entered)=CURDATE()"))
->groupBy('assigned_user_id')
->get();
This query should be like
select sum(total) as total_collect,collection_limit_c from `baid_collections` inner join `users_cstm` on `baid_collections`.`assigned_user_id` = `users_cstm`.`id_c` where assigned_user_id = '15426608-3ea5-f299-7a80-601bd06be2d9' and DATE(date_entered)=CURDATE() group by `assigned_user_id`
But last run query showing me
select sum(total) as total_collect,collection_limit_c from `baid_collection` inner join `users_cstm` on `baid_collections`.`assigned_user_id` = `users_cstm`.`id_c` where assigned_user_id = '15426608-3ea5-f299-7a80-601bd06be2d9' and DATE(date_entered)=CURDATE() is null group by `assigned_user_id`
In query is null giving problem i dont want is null in query
Use whereRaw instead of where like
$users = DB::table('baid_collections')
->select(DB::raw('sum(total) as total_collect,collection_limit_c'))
->join('users_cstm', 'baid_collections.assigned_user_id', '=', 'users_cstm.id_c')
->whereRaw("assigned_user_id = '{$userId}' and DATE(date_entered)=CURDATE()")
->groupBy('assigned_user_id')
->get();
It's creating a problem due to where needs atleast two parameters and you are just passing one parameter
Check this if it helps, write whereDate instead of add date in raw query.
if you are not using Carbon, you can also use php date("Y-m-d"), method to get date
DB::table('baid_collection')
->select(DB::raw('sum(total) as total_collect,collection_limit_c'))
->join('users_cstm', 'baid_collections.assigned_user_id', '=', 'users_cstm.id_c')
->where(DB::raw("assigned_user_id = '$userId'"))
->whereDate("date_entered", "=", Carbon::now()->toDateString())
->groupBy('assigned_user_id')->get();
You can try this
$users = DB::table('baid_collection')
->select(DB::raw('sum(total) as total_collect,collection_limit_c'))
->join('users_cstm', 'baid_collections.assigned_user_id', '=', 'users_cstm.id_c')
->where(DB::raw("assigned_user_id = '$userId' and DATE(date_entered) = '".date('Y-m-d')."'"))
->groupBy('assigned_user_id')
->get();

Refactor Laravel Query

I have a query that I have built, and I am trying to understand how I can achieve the same thing but in one single query. I am fairly new to Laravel and learning. Anyway someone could help me understand how I can achieve what I am after?
$activePlayerRoster = array();
$pickupGames = DB::table('pickup_games')
->where('pickupDate', '>=', Carbon::now()->subDays(30)->format('m/d/Y'))
->orderBy('pickupDate', 'ASC')
->get();
foreach ($pickupGames as $games) {
foreach(DB::table('pickup_results')
->where('pickupRecordLocatorID', $games->recordLocatorID)
->get() as $activePlayers) {
$activePlayerRoster[] = $activePlayers->playerID;
$unique = array_unique($activePlayerRoster);
}
}
$activePlayerList = array();
foreach($unique as $playerID) {
$playerinfo = DB::table('players')
->select('player_name')
->where('player_id', $playerID)
->first();
$activePlayerList[] = $playerinfo;
}
return $activePlayerList;
pickup_games
checkSumID
pickupDate
startTime
endTime
gameDuration
winningTeam
recordLocatorID
pickupID
1546329808471
01/01/2019
08:03 am
08:53 am
50 Minute
2
f47ac0fc775cb5793-0a8a0-ad4789d4
216
pickup_results
id
checkSumID
playerID
team
gameResult
pickOrder
pickupRecordLocatorID
1
1535074728532
425336395712954388
1
Loss
0
be3532dbb7fee8bde-2213c-5c5ce710
First, you should try to write SQL query, and then convert it to Laravel's database code.
If performance is not critical for you, then it could be done in one query like this:
SELECT DISTINCT players.player_name FROM pickup_results
LEFT JOIN players ON players.player_id = pickup_results.playerID
WHERE EXISTS (
SELECT 1 FROM pickup_games
WHERE pickupDate >= DATE_FORMAT(SUBDATE(NOW(), INTERVAL 30 DAY), '%m/%d/%Y')
AND pickup_results.pickupRecordLocatorID = recordLocatorID
)
Here I'm assuming you know what you're doing with this dates comparison, because it looks weird to me.
Now, let's convert it to Laravel's code:
DB::table('pickup_results')
->select('players.player_name')->distinct()
->leftJoin('players', 'players.player_id', '=', 'pickup_results.playerID')
->whereExists(function ($query) {
$query->select(DB::raw(1))
->from('pickup_games')
->where('pickupDate', '>=', Carbon::now()->subDays(30)->format('m/d/Y'))
->whereRaw('pickup_results.pickupRecordLocatorID = recordLocatorID');
})
->get();
Basically, I would reduce the query to its SQL variant to get directly at its core.
The essence of the query is
select `x` FROM foo WHERE id IN (
select distinct bar.id from bar join baz on bar.id = baz.id);
This can be interpreted in Eloquent as:
$thirtyDaysAgo = Carbon::now()->subDays(30)->format('m/d/Y');
$playerIds = DB::table('pickup_games')
->select('pickup_games.player_id')
->join(
'pickup_results',
'pickup_results.pickupRecordLocatorID',
'pickup_games.recordLocatorID')
->where('pickupDate', '>=', $thirtyDaysAgo)
->orderBy('pickupDate', 'ASC')
->distinct('pickup_games.player_id');
$activePlayers = DB::table('players')
->select('player_name')
->whereIn('player_id', $playerIds);
//>>>$activePlayers->toSql();
//select "player_name" from "players" where "player_id" in (
// select distinct * from "pickup_games"
// inner join "pickup_results"
// on "pickup_results"."pickupRecordLocatorID" = "pickup_games"."recordLocatorID"
// where "pickupDate" >= ? order by "pickupDate" asc
//)
From the resulting query, it may be better to refactor the join as relationship between the Eloquent model for pickup_games and pickup_results. This will help to further simplify $playerIds.

Yii2 subquery GROUP BY in active record

can I convert this query
"SELECT * FROM (SELECT * FROM blog_post ORDER BY data DESC) blog_post GROUP BY blog_id LIMIT 2"
into a Yii2 active record query?
Thx
Ms
Yes, you can do this.
Yii2 gave us a wonderful library support.
You can form custom sql query and pass this query in findBySql() like:
$sql = "Some query/nested query";
$result = ModelClass::findBySql($sql);
Visit Yii official documentation.
BlogPost::find()
->orderBy('data DESC')
->groupBy('blog_id')
->limit(2)
->all();
I suppose you can do in this way :
Ⅰ:create a subQuery where you select from.
$blogPostQuery = BlogPostModel::find()->orderBy(['data' => SORT_DESC]);
Ⅱ:Get activeRecord results. The from params is an exist Query.
$models = (new yii\db\Query)
->from(['blog_post ' => $blogPostQuery])
->groupBy(['blog_id'])
->limit(2)
->all();
ps:
see yii\db\query->from()-detail in Yii Api;
(public $this from ( $tables )) $tables can be either a string (e.g. 'user') or an array (e.g. ['user', 'profile']) specifying one or several table names··· or a sub-query or DB expression
Have a try!I hope it`s useful for you:))

How to Join same table in laravel

I wan to wirte a join query to connect same table, and without ON, but when i write it in laravel without on it is showing error
$key = DB::table('api_keys as ak')
->join('api_keys as bk','')
->where('ak.api_key', $api_key)->where('ak.user_id',0)
->pluck('api_key');
want to build the below query,
SELECT * FROM `api_keys` as ak
JOIN `api_keys` as bk
WHERE ak.`api_key`=$akey
and ak.`user_id`=$auser
and bk.`user_id`=$bsuer
and bk.`api_key`=$bkey
You must provide an ON clause for the join. More about where ON clauses are required can be found in this answer.
You can view the generated query using toSql() on a QueryBuilder object:
echo $key = DB::table('api_keys as ak')
->join('api_keys as bk','')
->where('ak.api_key', $api_key)->where('ak.user_id',0)
->toSql();
Which in your case returns:
select * from `api_keys` as `ak` inner join `api_keys` as `bk`
on `` `` where `ak`.`api_key` = ? and `ak`.`user_id` = ?
In your case it isn't totally clear what you are trying to achieve, but you might consider joining on api_key or the primary key of the api_keys table, if that is different:
$key = DB::table('api_keys as ak')
->join('api_keys as bk','ak.api_key', '=', bk.api_key)
->where('ak.api_key', $api_key)->where('ak.user_id',0)
->pluck('api_key');
DB::table('registerusers as a')
->join('registerusers as b', 'a.id', 'b.refer_id')
->where('a.username', 'b.username')
->where('b.id', 'a.refer_id')
->value('b.id');
without using on clause in laravel query builder you can use following
$key = DB::table(DB::raw('api_keys as ak, api_keys as bk'))
->where('ak.api_key', '=', $api_key)
->where('ak.user_id','=',0)
->where('ak.PK','=','bk.PK')
->pluck('ak.api_key')
where PK references to your table's primary key.
result will in your case.
select * from api_keys as ak, api_keys as bk where ak.api_key= 'api_key_value' and ak.user_id = 0 and ak.PK = bk.PK
I solved this by creating my own class and starting out with a base query which I modify to apply the join (using Laravel's joinSub function) as follows:
public function __construct()
{
$this->query = DB::table('question_responses as BASE');
}
public function applyFilter($questionId, $questionValue) {
$filterTableStr = 'filter_table_'.$questionId;
$filterIdStr = 'filter_id_'.$questionId;
$filterQuery = DB::table('question_responses AS '.$filterTableStr)
->select('survey_response_id AS '.$filterIdStr)
->where($filterTableStr.'.question_short_name', $questionId)
->where($filterTableStr.'.value', $questionValue);
$resultTableStr = 'result_table_'.$questionId;
$this->query = $this->query
->joinSub($filterQuery, $resultTableStr, function($join) use ($resultTableStr, $filterIdStr) {
$join->on('BASE.survey_response_id', '=', $resultTableStr.'.'.$filterIdStr);
});
}
After applying my required filters I can just call $this->query->get() as normal to obtain the result.
The important part was to make sure that each resulting table and join fields has unique names.
With this method I can apply unlimited filters to my base query.

Resources