I am trying to increase the speed of my Laravel 5.4 sql query by using joins, which I've never used before. I currently have the query working and returning results, my issue is that I get like each results around 8 times. Ex: I get the same 2001 Chevrolet Silverado 8 times in my array. If anybody could help me out I would really appreciate it. Thanks
My query + collection:
$tmp = DB::table('inventories'
)->join(
'vehicles', 'vehicles.id', '=', 'inventories.id'
)->join(
'vimages', 'vimages.vehicle_id', '=', 'inventories.id'
)->where(
'inventories.dealer_id', '=', $dealer_id
)->where(
'inventories.is_active', '=', 1
)->where(
'inventories.is_deleted','=', 0
)->select(
'inventories.stock_number','inventories.vehicle_id','vehicles.year','vehicles.make','vehicles.model','vehicles.vin','inventories.vehicle_status',
'inventories.cost','inventories.search_meta','vimages.name'
);
$data = collect();
$pmt = $tmp->get();
// return json_encode( $pmt );
// logger( sprintf('# of rows returned: %s', $pmt->count() ) );
$pmt->each( function($row) use(&$data) {
// logger( sprintf('Row : %s', $row->toJson() ));
$data->push( array(
'stock_number' => $row->stock_number,
'vehicle_id' => $row->vehicle_id,
'year' => $row->year,
'make' => $row->make,
'model' => $row->model,
// 'trim' => $row->trim,
'vin' => $row->vin,
'status' => $row->vehicle_status,
// 'purchase_price' => $row->purchase_price,
'cost' => $row->cost,
// 'retail_price' => $row->retail_price,
'search_meta' => $row->search_meta,
// 'images' => $row->getFirstImage()
'images' => $row->name
// 'interior_color' => $row->vehicle()->first()->interior_color,
// 'exterior_color' => $row->vehicle()->first()->exterior_color,
// 'firstImg' => $row->getFirstImage()
// 'images' => Vimage::select('vehicle_id','name'
// )->where(
// 'dealer_id', '=', $row->dealer_id
// )->where(
// 'vehicle_id', '=', $row->vehicle_id
// )->limit(1)->get()
));
});
Example of my array:
https://i.imgur.com/FOphST8.png
I don't see your db table but I think there is problem in first join statment:
you should use
->join('vehicles', 'vehicles.id', '=', 'inventories.vehicle_id' )
instead of
->join('vehicles', 'vehicles.id', '=', 'inventories.id' )
also second join should be like
->join('vimages', 'vimages.vehicle_id', '=', 'vehicles.id')
instead of
->join('vimages', 'vimages.vehicle_id', '=', 'inventories.id')
It sounds trivial but this should work:
$tmp = DB::table('inventories'
)->join(
'vehicles', 'vehicles.id', '=', 'inventories.id'
)->join(
'vimages', 'vimages.vehicle_id', '=', 'inventories.id'
)->where(
'inventories.dealer_id', '=', $dealer_id
)->where(
'inventories.is_active', '=', 1
)->where(
'inventories.is_deleted','=', 0
)->selectRaw("DISTINCT inventories.stock_number, inventories.vehicle_id,
vehicles.year, vehicles.make, vehicles.model, vehicles.vin,
inventories.vehicle_status, inventories.cost,
inventories.search_meta, vimages.name"
);
Update: forgot to delete the single quotes in selectRaw
Figured it thanks to #Devon. Added another where statement to query to only get first image.
Thanks
)->where('vimages.sequence','=', 0
Related
I am having some trouble in Laravel using the query builder to select users based on two where clauses.
The first where clause would contain multiple where statements to select a user based on some conditions. If this fails in the OR part I would like to check simply if the user ID is in the array.
Would be grateful for some advice on how I could achieve this.
Thanks.
$rs = DB::table('tblUser')
->select('name')
->where(function($q) {
$q->where(function($q){
$q->where('fid', '=', $this->argument('fid'))
->where('type', '<', 10)
})
->orWhereIn('id', $userIdSArray);
})
->get();
$userIdSArray = [ '2', '4', '5' ];
$rs = DB::table( 'Users' )
->select( 'name' )
->where( function ( $q ) use ( $userIdSArray ) {
$q->where( function ( $q ) {
$q->where( 'fid', '=', $this->argument( 'fid' ) )
->where( 'type', '<', 10 );
})
->orWhereIn( 'id', $userIdSArray );
})
->get();
I think you need to pass $userIdSArray in Query builder . And You also forgot (;) after [->where( 'type', '<', 10 )]
I have a question i have 4 tables
Deals
Lists
Lists_Galleries
List_has_deals
Lists_has_gallery
I need to obtain the img_src_list what is in the List_Galleries but from deals.
I have this var in this time
$query = ListsDeals::where( $matchDeals )
->where('stock', '>', 0)
->orwhere( $matchOtherDeals )
->whereDate('end_date', '>', date('Y-m-d'))
->limit( 4 )
->offset( 0 )
->orderBy( 'start_date' );
$deals = $query->join( 'list_has_deals', 'deals.id', '=', 'list_has_deals.deal_id' )
->join( 'lists', 'list_has_deals.list_id', '=', 'lists.id' )
->join( 'list_has_gallery', 'lists.id', '=', 'list_has_gallery.list_id' )
->join( 'lists_galleries', 'list_has_gallery.gallery_id', '=', 'lists_galleries.id' )->get();
This Give me the results but how i have the same name in all tables for example title for deals and lists that overwrite the names and dont get the values correct, how i can obtain certain columns without overwrite the others? regards.
UPDATE
This give me always the same deal for all results.
$deals = $query->join( 'list_has_deals', 'deals.id', '=', 'list_has_deals.deal_id' )
->join( 'lists', 'list_has_deals.list_id', '=', 'lists.id' )
->join( 'list_has_gallery', 'lists.id', '=', 'list_has_gallery.list_id' )
->join( 'lists_galleries', 'list_has_gallery.gallery_id', '=', 'lists_galleries.id' )
->select([ 'deals.id as deal_id', 'deals.stock as stock', 'deals.price as price', 'deals.price_reduced as price_reduced', 'deals.img_src as img_src', 'deals.title_deal as deal_title' ])->get();
UPDATE
$deals = $query->join( 'list_has_deals', 'deals.id', '=', 'list_has_deals.deal_id' )
->join( 'lists', 'list_has_deals.list_id', '=', 'lists.id' );
$other = $deals->join( 'list_has_gallery', 'lists.id', '=', 'list_has_gallery.list_id' )
->join( 'lists_galleries', 'list_has_gallery.gallery_id', '=', 'lists_galleries.id' )
->select([ 'deals.id', 'deals.stock', 'deals.price', 'deals.price_reduced', 'deals.img_src', 'deals.title_deal', 'lists_galleries.img_src_list' ])
->addSelect([ 'lists_galleries.img_src_list' ])
->get();
You can use select() to choose only those columns you want, and use aliases to rename any that clash:
$query->select(['lists.title AS title', 'lists_galleries.name AS name', 'lists.id AS id'])->get();
That way you can cherry-pick only those columns you need and deal with clashes easily.
i have this
public function deals(){
$matchThese = [ 'suspended' => 0, 'status' => 1, 'approved' => 1 ];
$deals = ListsDeals::where( $matchThese )->orderBy( 'start_date' )->get();
$list = DB::table( 'lists' )
->join( 'list_has_deals', 'lists.id', '=', 'list_has_deals.list_id' )
->where( 'list_has_deals.deal_id', '=', 12)
->select( 'lists.id' )
->get();
$categories = DB::table( 'lists_categories' )
->join( 'list_has_categories', 'lists_categories.id', '=', 'list_has_categories.category_id' )
->where( 'list_has_categories.list_id', '=', $list[0]->id )
->select( 'lists_categories.title' )
->get();
return view( "deals" )
->with( "deals", $deals )
->with( "categories", $categories );
}
I want to obtain the value of title for the categories in lists, but first i need to obtain the deals for the lists in less words
I have
Deals - Lists - lists_has_deals
Categories - Lists - lists_has_deals
Both are belongsToMany, i want obtain in the deals the categories belonging to the list that is associated with the offer.
In my example that works fine but the 12 need to be a foreach of the $deals not be number static, thanks for the help.
Try using a has many through or intermediate pivot table on lists_has_deals. If I'm understanding your question, lists should have the necessary reference to both deals and categories.
https://laravel.com/docs/5.4/eloquent-relationships#has-many-through
https://laravel.com/docs/5.4/eloquent-relationships#many-to-many
specifically withPivot()
I am having a really tough time figuring out another approach to do search querys on my site. At the moment i have search critierias for "Min size, Max size, City, street, Min. price, Max. price.
So i have these queries (build using Laravel standard):
if (!empty($by) && empty($adresse) && empty($minstor) && empty($maxstor))
{
$users = User::where('pris', '<', $maxpris)->where('pris', '>', $minpris)->where('by', '=', $by)->orderBy('created_at', 'DESC')->get();
}
elseif (!empty($by) && !empty($adresse) && empty($minstor) && empty($maxstor))
{
$users = User::where('pris', '<', $maxpris)->where('pris', '>', $minpris)->where('by', '=', $by)->where('adresse', '=', $adresse)->orderBy('created_at', 'DESC')->get();
}
elseif (empty($by) && !empty($adresse) empty($minstor) && empty($maxstor))
{
$users = User::where('pris', '<', $maxpris)->where('pris', '>', $minpris)->where('adresse', '=', $adresse)->orderBy('created_at', 'DESC')->get();
}
else
{
$users = User::where('pris', '<', $maxpris)->where('pris', '>', $minpris)->orderBy('created_at', 'DESC')->get();
}
All of this simply for the user being able to search for the for the critirias above, but if i want to add several more feautures, i can just imagine how many different if functions i will need to run in order to get all the specific inputs etc. It will evovle eksponentially really quick.
How can i get around this problem without having to create hundreds of different if else statements in order to return the correct query?
You could set up an array of your filters with their corresponding operator. Then iterate over the filters that were passed and running the them (This hasn't been tested but should get you headed in the right direction):
$available_queries = [
['input' => 'maxpris', 'operator' => '<', 'field' => 'pris'],
['input' => 'minpris', 'operator' => '>', 'field' => 'pris'],
['input' => 'by', 'operator' => '=', 'field' => 'by'],
['input' => 'adresse', 'operator' => '=', 'field' => 'addresse'],
]
$query = User::orderBy('created_at', 'DESC');
foreach($available_queries as $filter){
if(request()->input($filter['input'])){
$query = $query->where(
$filter['field'],
$filter['operator'],
request()->input($filter['input'])
);
}
}
$users = $query->get();
EDIT: I found an error in my original script. Updated to fix the error and make more readable.
You can to do like this
$q = User::query();
if (\Input::has('name')) {
$q->where('name', \Input::get('name'));
}
if (\Input::has('address')) {
$q->where('address', \Input::get('address'));
}
...
You can iterate it in loop like this,
foreach($request->all() as $req_field => $req_data) {
if (\Input::has($req_field)) {
$q->where($req_field, \Input::get($req_field));
}
}
p.s. or you can iterate it in scope ...
then
$items = $q->orderBy('id', 'desc')->get();
For example I have the following query which updates a new row:
$query->where('email', '=', $user->email)->where('card_uid', '=', $k)
->update( array('email' => $user->email, 'card_uid' => $k, 'have_quantity' => ($card->have_quantity+$v)) );
I'd like to retrieve the updated (or inserted) row. I tried the following but it doesn't work:
$row = $query->where('email', '=', $user->email)->where('card_uid', '=', $k)
->update( array('email' => $user->email, 'card_uid' => $k, 'have_quantity' => ($card->have_quantity+$v)) )
->get();
How can I retrieve the row I am updating or inserting easily?
You can try using the same query builder instance for the update first and then run the select query. (You can't do it the way you tried because update() returns the number of affected rows)
$query->where('email', '=', $user->email)->where('card_uid', '=', $k);
$query->update(array('email' => $user->email, 'card_uid' => $k, 'have_quantity' => ($card->have_quantity+$v)))
$row = $query->get();