selecting all fields from secondary table in eloquent - php

Is there any reason why my query doesn't end?, I try to get all the values from the secondary table in a join in eloquent:
Product::leftJoin('brands', 'products.brand_id', '=', 'brands.id')
->leftJoin('product_categories', function($query) use ($parent){
$query->on('products.category_id', '=', 'product_categories.id')
->where('product_categories.parent_id', $parent);
})
->selectRaw('brands.*')
->groupBy('brands.id')
->get();
If I select products.* the query goes fine, but with brands.* it never ends, Does someone knows what is happening?
If i run the sql directly in phpmyadmin, it gives me the result.
What i need with this query is to get all brands with existing products that its category has parent_id = $parent

Well i don't know why eloquent has a problem with getting the fields from the second table, but I used query builder so this query work. I leave my "solution", maybe it is useful to someone:
$brands = Product::leftJoin('brands', 'products.brand_id', '=', 'brands.id')
->leftJoin('product_categories', function($query) use ($parent){
$query->on('products.category_id', '=', 'product_categories.id')
->where('product_categories.parent_id', $parent);
})
->selectRaw('brands.*')
->groupBy('brands.id');
$bindings = $brands->getBindings();
$sql = $brands->toSql();
$sql = vsprintf(str_replace('?', '%s', $sql), $bindings);
$brands = \DB::select($sql);

Related

Laravel get one to many with limit by DB query builder

I have a products table that is connected through model_has_attachments with attachments table. I need to connect first attachment to each product record thought the query builder, but for some reason it just give me few records with model_has_attachments ids and rest is the null
my query builder look as:
$products = DB::table('products')->
leftJoin(DB::raw('(select `model_id`, `attachment_id` from model_has_attachments where model_has_attachments.model_id = id) as model_has_attachments'), 'model_has_attachments.model_id', 'products.id')->
leftJoin('attachments', 'model_has_attachments.attachment_id', '=', 'attachments.id')->
select('products.id', 'products.square', 'products.height', 'products.address', 'products.rooms', 'products.title', 'products.description', 'model_has_attachments.model_id as id_model', 'model_has_attachments.attachment_id')->
where([
['products.deleted_at', '=', null],
]);
I've tried to add limit = 1 in the DB::raw but it just give me the first record of the products table, not a joined table. Can you tell me why?
I also tried different approach, but it takes all the record of attachments which result duplicate products records if product has more than one attachment. I also have tried to add ->limit(1) at the end but it just ignores the method.
leftJoin('model_has_attachments', function ($join) {
$join->on('products.id', '=', 'model_has_attachments.model_id')->where('model_has_attachments.model_type', '=', Product::class);
})->
``
//try this
$products = Product::leftJoin('model_has_attachments', 'products.id', '=', 'model_has_attachments.model_id')
->leftJoin('attachments', 'attachments.id', '=', 'model_has_attachments.attachment_id')
->addSelect('products.*', 'attachments.id as attachment_id')
->where('attachments.is_active',1)
->get();

Selecting items with join and without foreign key

I have query which gets each user's record from blacklist table and relations to them from rules table.
It looks like that:
$result1 = DB::table('blacklist')
->join('rules', 'blacklist.rule_id', '=', 'rules.id')
->select('blacklist.*', 'rules.clicks', 'rules.minutes')
->groupBy('blacklist.address')
->where('blacklist.user_id', JWTAuth::user()->id)
->get();
However I set field blacklist.rule_id as CAN BE NULL. Above query doesn't get records which have blacklist.rule_id == null(only these with values).
I have second query for that purpose:
$result2 = DB::table('blacklist')
->select('blacklist.*')
->groupBy('blacklist.address')
->where('blacklist.user_id', JWTAuth::user()->id)
->where('blacklist.rule_id', null)
->get();
But how to do it in one query?
It is actually an leftJoin instead of join:
$result1 = DB::table('blacklist')
->leftJoin('rules', 'blacklist.rule_id', '=', 'rules.id')
->select('blacklist.*', 'rules.clicks', 'rules.minutes')
->groupBy('blacklist.address')
->where('blacklist.user_id', JWTAuth::user()->id)
->get();
try this
$result2 = DB::table('blacklist')
->select('blacklist.*')
->groupBy('blacklist.address')
->where(function ($result2) {
$result2->where('blacklist.user_id', JWTAuth::user()->id)
->orWhereNull('blacklist.user_id');
}
->get();

How to make two Laravel Eloquent queries into a single one (so I hit the database once instead of 2 times)

Say I have 3 tables in my database.
'my_recipe', 'my_inventory' and 'ingredient'.
The 'my_recipe' table stores a list of raw_id's based on the 'ingredient' table and the 'quantity' need for the recipe. The 'my_inventory' table stores a list of raw_id's and 'have_quantity'.
So let's take a look at what I currently have at the moment. I have the following 2 queries:
First Query:
$recipe = DB::table('my_recipe as tA')
->leftJoin('ingredient as tB', 'tA.raw_id', '=', 'tB.raw_id')
->select('tA.user as user', 'tA.raw_id as raw_id', 'tA.quantity as quantity',
'tB.ingredient_name as ingredient_name')
->where('user', '=', $user)
->where('raw_id', '=', $raw_id)
->get();
Second Query:
$inventory = DB::table('my_inventory as tA')
->leftJoin('ingredient as tB', 'tA.raw_id', '=', 'tB.raw_id')
->select('tA.user as user', 'tA.have_quantity as have_quantity',
'tB.ingredient_name as ingredient_name')
->where('user', '=', $user)
->get();
The first query returns results that look something like this:
{"user":"jack","raw_id":"853","quantity":2,"ingredient_name":"apple"},
{"user":"jack","raw_id":"853","quantity":4,"ingredient_name":"peach"}
The second query returns results that look something like this:
{"user":"jack","have_quantity":30,"ingredient_name":"apple"},
{"user":"jack","have_quantity":20,"ingredient_name":"apple"},
{"user":"jack","have_quantity":10,"ingredient_name":"apple"},
{"user":"jack","have_quantity":1,"ingredient_name":"peach"},
{"user":"jack","have_quantity":1,"ingredient_name":"peach"}
Notice in the second query results I have to get the sum of the ingredients based on the 'ingredient_name' for my ideal output.
How can I get my ideal output in a single query?
My ideal output would look something like this:
{"user":"jack","raw_id":"853","quantity":2,"ingredient_name":"apple","have_quantity":60},
{"user":"jack","raw_id":"853","quantity":4,"ingredient_name":"peach","have_quantity":2}
It's basically the results of the first query with 'have_quantity' totals from the second query.
EDIT:
my_recipe Model:
'user', 'raw_id', 'quantity'
my_inventory Model:
'user', 'raw_id', 'have_quantity'
ingredient Model:
'raw_id', 'ingredient_name'
Note: In the ingredient model there can be rows with the same 'ingredient_name' but have different 'raw_id'.
Based on our chat conversation I managed to get some extra information on the table structure and what was needed to do to get the wanted results.
For those interested the information can be found here
Anyway I ended up creating the query like this:
SELECT
my_recipe.user AS user,
my_recipe.raw_id AS raw_id,
my_recipe.quantity AS quantity,
ingredient.ingredient_name AS ingredient_name,
IFNULL(SUM(my_inventory.have_quantity),0) AS have_quantity
FROM my_recipe
LEFT JOIN ingredient USING(raw_id)
LEFT JOIN ingredient AS ingredients USING(ingredient_name)
LEFT JOIN my_inventory ON my_inventory.raw_id = ingredients.raw_id
WHERE my_recipe.recipe_id = 853
AND my_recipe.user = 'jack'
AND my_inventory.user = 'jack'
GROUP BY ingredient_name;
Now converting into the needed structure:
$inventory = DB::table('my_recipe')
->leftJoin('ingredient', 'my_recipe.raw_id', '=', 'ingredient.raw_id')
->leftJoin('ingredient AS ingredients', 'ingredient.ingredient_name', '=', 'ingredients.ingredient_name')
->leftJoin('my_inventory', 'my_inventory.raw_id', '=', 'ingredients.raw_id')
->select(DB::raw('my_recipe.user AS user,my_recipe.raw_id AS raw_id,my_recipe.quantity AS quantity,ingredient.ingredient_name AS ingredient_name,IFNULL(SUM(my_inventory.have_quantity),0) AS have_quantity'))
->where('my_recipe.recipe_id', '=', $recipe_id)
->where('my_recipe.user', '=', $user)
->where('my_inventory.user', '=', $user)
->groupBy('ingredient_name')
->get();
Maybe this can solve you problem
//replace count by sum
$inventory = DB::table('my_inventory as tA')
->leftJoin('ingredient as tB', 'tA.raw_id', '=', 'tB.raw_id')
->leftJoin('my_recipe as tC', 'tC.raw_id', '=', 'tB.raw_id')
->select(DB::raw('tA.user as user, tB.ingredient_name as ingredient_name, SUM(tA.have_quantity) have_quantity'))
->where('user', '=', $user)
->groupBy('tB.ingredient_name, tA.user')
->get();
Let's try this:
$result = DB::table('ingredient as ing')
->rightJoin('my_recipe as rcp', 'ing.raw_id', '=', 'rcp.raw_id')
->rightJoin('my_inventory as inv', 'ing.raw_id', '=', 'inv.raw_id')
->select(DB::raw('
rcp.user as user,
ing.ingredient_name as ingredient_name,
rcp.have_quantity quantity,
SUM(inv.have_quantity) have_quantity
'))
->where('rcp.user', '=', $user)
->where('rcp.raw_id', '=', $raw_id)
->groupBy('rcp.user, ing.ingredient_name')
->get();

Convert mysql query into Eloquent laravel query

I am trying to make the following query in laravel:
SELECT a.name AS subname, a.area_id, b.name, u. id, u.lawyer_id,u.active_search,
FROM subarea a
LEFT JOIN user_subarea u ON u.subarea_id = a.id
AND u.user_id = ?
LEFT JOIN branch b ON a.area_id = b.id
The idea is to obtain the subareas and see if the search is activated by the user.
The user_subarea table might have a record that matches the id of the subarea table where the active_search is equal to 0 or 1. If it doesn't exist I would like the query to return null.
While I was able to achieve this in raw SQL when I try the same with eloquent in Laravel I am not returning any value. I have done the following:
$query = DB::table('subarea')
->join('user_subarea', function($join)
{
$value = \Auth::user()->id;
$join->on( 'subarea.id', '=', 'user_subarea.subarea_id')->where('user_subarea.user_id', '=',$value);
})
->leftJoin('branch', 'subarea.area_id', '=', 'branch.id')
->select('branch.name', 'subarea.name as subarea', 'user_subarea.active_search_lawyer', 'user_subarea.id' )
->get();
Any help will be much appreciated.
I found by myself the answer it was just to add a lefjoin in the first join. It is not in the laravel docs but works too.
$query = DB::table('subarea')
->lefjoin('user_subarea', function($join)
{
$value = \Auth::user()->id;
$join->on( 'subarea.id', '=', 'user_subarea.subarea_id')->where('user_subarea.user_id', '=',$value);
})
->leftJoin('branch', 'subarea.area_id', '=', 'branch.id')
->select('branch.name', 'subarea.name as subarea', 'user_subarea.active_search_lawyer', 'user_subarea.id' )
->get();
Try this one, If you get a problem, please comment.
$value = \Auth::user()->id;
$query = DB::table('subarea')
->where('user_subarea.user_id', '=',$value)
->leftJoin('user_subarea', 'subarea.id', '=', 'user_subarea.subarea_id')
->leftJoin('branch', 'subarea.area_id', '=', 'branch.id')
->select('subarea.name AS subname','subarea.area_id', 'branch.name', 'user_subarea.id','user_subarea.lawyer_id','user_subarea.active_search')
->get();

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