Nested SQL Query in Laravel Controller - php

I have two queries running in my controller. I need a value from the first query to be passed into the second. I want the result of both these queries sent to my view.
public function jobs()
{
$query = DB::table("dbQuotes")
->leftJoin("dbACT", "dbQuotes.act_id", "=", "dbACT.ID")
->leftJoin("dbOpps", "dbQuotes.act_id", "=", "dbOpps.contactID")
->leftjoin('dbBids', 'dbQuotes.act_id','=',
DB::raw('dbBids.quote_id AND dbBids.user_id = '. Auth::user()->id))
->where("dbQuotes.active", "=", "1")
->select("dbQuotes.*", "dbACT.*", "dbBids.*",
(DB::raw('date_format(dbQuotes.posted_date, "%d/%m/%Y %H:%i") as posted_date')),
(DB::raw('date_format(dbOpps.expected_date, "%d/%m/%Y") as expected_date')))
->groupBy("dbQuotes.id")
->orderBy("posted_date", "desc")
->get();
$passinvaluehere = $query->dbQuotes.act_id
$bids = DB::table("dbBids")
->where("quote_id", "=", $passinvaluehere)
->get();
return view('jobs', ['query' => $query,'bids' => $bids]);
}
My query works and the view is established in the correct way if I replace the passed value with a number, i.e "8763". My question is how, within this function, can I pass the value/s of dbQuotes.act_id into this second query?
***UPDATED Code from answer: [error Call to a member function lists() on a non-object]
public function jobs()
{
$query = DB::table("dbQuotes")
->leftJoin("dbACT", "dbQuotes.act_id", "=", "dbACT.ID")
->leftJoin("dbOpps", "dbQuotes.act_id", "=", "dbOpps.contactID")
->leftJoin('dbBids', 'dbQuotes.act_id','=',
DB::raw('dbBids.quote_id AND dbBids.user_id = '. Auth::user()->id))
->where("dbQuotes.active", "=", "1")
->select("dbQuotes.*", "dbACT.*", "dbBids.*",
(DB::raw('date_format(dbQuotes.posted_date, "%d/%m/%Y %H:%i") as posted_date')),
(DB::raw('date_format(dbOpps.expected_date, "%d/%m/%Y") as expected_date')))
->groupBy("dbQuotes.id")
->orderBy("posted_date", "desc")
->get();
$act_id = $query->lists('act_id');
$bids = DB::table("dbBids")
->whereIn("quote_id", $act_id)
->get();
return view('jobs', ['query' => $query,'bids' => $bids]);
}

If you have multiple records (as per the ->get() method) you have two ways: either you loop over the Collection and make a query each iteration (bad) or you create an array of ids and use a whereIn in the second query (better):
$passinvaluehere = $query->lists('act_id');
// https://laravel.com/docs/5.2/queries#retrieving-results
// this creates and array of `act_id` s
$bids = DB::table("dbBids")
->whereIn("quote_id", $passinvaluehere)
->get();
// you now have a Collection of multiple $bids
If you expect only a single records from your first query, you need to change the fetcher method, using first() instead, or else take only the first element of your actual collection, something like first($query) or $query[0]
$query = DB::table("dbQuotes")
....
->first();
$passedvaluehere = $query->act_id;

Related

Is there any way to get two different results with single query based on condition?

I am trying to get two different results from single query but the problem is both conditions get applied on last query.
for example
$getUser = User::join('role_user','role_user.user_id','users.id')
->select('users.id','users.name','users.email','users.identity_status','users.email_verified_at','role_user.role_id')
->where('role_user.role_id',2)
->whereNotNull('users.email_verified_at');
$newMailUsers = $getUser->where('new_mail',0)->get();
$topSellingMailUsers = $getUser->where('topselling_mail',0)->get();
but when i checked sql query of $topSellingMailUsers i saw that both the conditions of new_mail and topselling_mail applied in $topSellingMailUsers query what i want is it should not consider mail condition in query.
how can i get two different results of $newMailUsers, $topSellingMailUsers based on both conditions separately.
Every time you use where() method you are mutating $getUser query builder.
You can chain your query builder with clone() method and this will return another query builder with the same properties.
$getUser = User::join('role_user','role_user.user_id','users.id')
->select('users.id','users.name','users.email','users.identity_status','users.email_verified_at','role_user.role_id')
->where('role_user.role_id',2)
->whereNotNull('users.email_verified_at');
$newMailUsers = $getUser->clone()->where('new_mail',0)->get();
$topSellingMailUsers = $getUser->clone()->where('topselling_mail',0)->get();
you need to clone Builder object to reuse it
$selectFields = [
'users.id',
'users.name',
'users.email',
'users.identity_status',
'users.email_verified_at',
'role_user.role_id'
];
/** #var Illuminate\Database\Eloquent\Builder */
$getUser = User::join('role_user', 'role_user.user_id', 'users.id')
->select($selectFields)
->where('role_user.role_id', 2)
->whereNotNull('users.email_verified_at');
$newMailUsers = (clone $getUser)->where('new_mail', 0)->get();
$topSellingMailUsers = (clone $getUser)->where('topselling_mail', 0)->get();
Well, if you have relations set up on models will be easier, but still can do it:
// Let's say you pass sometimes the role_id
$role_id = $request->role_id ?? null;
$getUser = User::join('role_user','role_user.user_id','users.id')
->select('users.id','users.name','users.email','users.identity_status','users.email_verified_at','role_user.role_id')
// ->where('role_user.role_id',2) // replaced with ->when() method
->when($role_id, function ($query) use ($role_id){
$query->where('role_user.role_id', $role_id);
})
->whereNotNull('users.email_verified_at');
This way it will return users with ALL ROLES or if ->when(condition is TRUE) it will return users with the role id = $role_id.
You can use multiple ->when(condition, function(){});
Have fun!
Instead of firing multiple queries you can do it in a single query as well by using collection method as like below.
$users = User::join('role_user','role_user.user_id','users.id')
->select('users.id','users.name','users.email','users.identity_status','users.email_verified_at','role_user.role_id', 'new_mail', 'topselling_mail')
->where('role_user.role_id',2)
->where(function($query) {
$query->where('new_mail', 0)->orWhere('topselling_mail', 0);
})
->whereNotNull('users.email_verified_at')
->get();
$newMailUsers = $users->where('new_mail',0)->get();
$topSellingMailUsers = $user->where('topselling_mail',0)->get();

How can I used "if" condition in "whereIn" in laravel

Below is my query which one i used and working fine for me.
if($t_requested['category_id'])
{
$t_query_condition['p.category_id'] = $t_requested['category_id'];
}
if($t_requested['brand_id'])
{
$t_query_condition['p.brand_id'] = $t_requested['brand_id'];
}
$browseData = DB::table('products as p')
->leftjoin('categories as cp', 'p.category_id', '=', 'cp.id')
->leftjoin('brands as bp', 'p.brand_id', '=', 'bp.id')
->select('p.id as product_id','p.name as product_name','cp.title as category_name','bp.name as brand_name','p.product_weight',
'p.short_description','p.product_price','p.special_price','p.stock_quantity')
->orderBy('p.created_by', "desc")
->offset(0)
->limit(10)
->where($t_query_condition)
->get();
but Now i have getting multiple id in "category_id" and "brand_id", i want to used whereIn but it used with of condition. if i get category_id or brand_id null then it's skip.
thanks in advance.
Try this query hope you will get result
$browseData = DB::table('products as p')
->select('p.id as product_id','p.name as product_name','cp.title as category_name','bp.name as brand_name','p.product_weight',
'p.short_description','p.product_price','p.special_price','p.stock_quantity')
->leftjoin('categories as cp', 'p.category_id', '=', 'cp.id')
->leftjoin('brands as bp', 'p.brand_id', '=', 'bp.id')
->orderBy('p.created_by', "desc");
if($t_requested['category_id'])
{
$browseData->whereIn('p.category_id',$t_requested['category_id']);
}
if($t_requested['brand_id'])
{
$browseData->whereIn('p.brand_id',$t_requested['brand_id']);
}
$result=browseData->offset(0)->limit(10)->get();
I think it is very simple, you have to pass array of values instead of one value
I have tried to write options for achieve this, you have to follow which is suitable for you
if($t_requested['category_id'])
{
$t_query_condition['p.category_id'] = $t_requested['category_id']; // it should be array OR
$t_query_condition['p.category_id'] = explode(",",$t_requested['category_id']); // if you get value comma saperated
$t_query_condition['p.category_id'] = explode(",",$t_requested['category_id']); // if you get value comma saperated
$t_query_condition['p.category_id'] = [$t_requested['category_id']]; // if you want to convert one value into array
}

How to get an array result set from Laravel where condition

I am trying to get a result set from a laravel eloquent query whereby I match a column against a list of values in an array.
$authenticated_operation_ids = AccessControl::where('user_id', '=', $user_id)
->where('entity_type_id', '=', $operation_entity_id)
->pluck('entity_access_id')->toArray();
$authenticated_operations = Operation::whereIn('id', $authenticated_operation_ids);
return view('page.index')->withOperations($authenticated_operations);
You can try it as:
$authenticated_operation_ids = AccessControl::where('user_id', '=', $user_id)->where('entity_type_id', '=', $operation_entity_id)->pluck('entity_access_id')->toArray();
$authenticated_operations = Operation::whereIn('id', $authenticated_operation_ids)->get();
return view('page.index')->withOperations($authenticated_operations);
Add get() at the end of the query.
1) pluck returns a single value from a single row. You want lists to get a single column from multiple rows. toArray may not be needed, as it returns an array of values
$authenticated_operation_ids = AccessControl::where('user_id', '=', $user_id)
->where('entity_type_id', '=', $operation_entity_id)
->lists('entity_access_id');
2) You're forgetting to actually retrieve the rows in your second line:
$authenticated_operations = Operation::whereIn('id', $authenticated_operation_ids)
->get();
You have to call get() function on the result set to obtain results. The modified code will be like
$authenticated_operation_ids = AccessControl::where('user_id', '=', $user_id)->where('entity_type_id', '=', $operation_entity_id)->get()->pluck('entity_access_id');
$authenticated_operations = Operation::whereIn('id', $authenticated_operation_ids)->get();
return view('page.index')->withOperations($authenticated_operations);
or you can use a cursor to process it.

Laravel: For each where clause

I'm trying to return a query that has an arbitrary amount of where clauses based on the number of tags a user submits.
//unknown number of ids to query on
$tag_ids = array(1,5);
//multiple joins with closure
$items = DB::table('archives_items_metadata')->join('tags', 'archives_items_metadata.tag_id', '=', 'tags.id')->join('archives_items', 'archives_items_metadata.archive_item_id', '=', 'archives_items.id')->join('items', 'archives_items.item_id', '=', 'items.id')
->where(function ($query) use ($tag_ids) {
foreach ($tag_ids as $tag_id)
{
$query->where('archives_items_metadata.tag_id', $tag_id);
}
})->get();
The result I get is an empty array even though when I try array(1) or array(5) by themselves, they both return the same item. What am I missing?
EDIT::
I'm looking to return items that have each of the tag ids specified. The reference of items to tags is stored on the archives_items_metadata table. How can I get the result I'm expecting, and what's the most efficient way to accomplish this?
You are looking to do a WHERE tag_id IN (1, 2, 3) style clause laravel has the whereIn($col, $vals) builder function.
->whereIn('archives_items_metadata.tag_id', $tag_ids)
search for "whereIn" in the official docs
$tag_count = count($tag_ids);
$items = DB::table('archives_items')->join('archives_items_metadata', 'archives_items_metadata.archive_item_id', '=', 'archives_items.id')->join('tags', 'archives_items_metadata.tag_id', '=', 'tags.id')
->whereIn('archives_items_metadata.tag_id', $tag_ids)->whereNull('archives_items_metadata.deleted_at')
->groupBy('archives_items_metadata.archive_item_id')->havingRaw('count(*)='.$tag_count->get();

laravel using query builder without chaining

I have a query builder that works:
$article = Page::where('slug', '=', $slug)
->where('hide', '=', $hidden)
->first();
But I want to only add the second where statement if hidden is equal to 1. I've tried the code below which shows the logic of what I'm trying to do, but it doesn't work.
$article = Page::where('slug', '=', $slug);
if ($hidden == 1) {
$article->where('hide', '=', 1);
}
$article->first();
I'm using Laravel 4, but I think the question still stands with Laravel 3.
Yeah there's a little "gotcha" with Eloquent and the query builder. Try the code below ;)
$query = Page::where('slug', '=', $slug);
if ($hidden == 1) {
$query = $query->where('hide', '=', 1);
}
$article = $query->first();
Note the assigning of $query within the conditional. This is becuase the first where (statically called) returns a different object to the query object within the conditional. One way to get around this, I believe due to a recent commit, is like so:
$query = Page::where('slug', '=', $slug)->query();
This will return the query object and you can do what you want as per normal (Instead of re-assigning $query).
Hope that helps.

Categories