exists query does not return relevant result - sql

I have a Laravel application with this Eloquent query:
$products = Product::where('name', 'LIKE', "%{$value}%")
->whereHas('categories', function($q) {
$q->where( 'slug', 'tonery-cartridge' );
})->with('manufacturer')
->with('sm_image')
->orderBy('created_at','DESC')
->take(10)
->get();
This code generates the sql command like:
select * from `products` where `name` LIKE '%can%'
and exists (
select * from `categories` inner join `category_product`
on `categories`.`id` = `category_product`.`category_id`
where `products`.`id` = `category_product`.`product_id`
and `slug` = 'tonery-cartridge'
)
order by `created_at` desc limit 10
I am sure there are products which name contains "can" string and which belongs to the category with slug "tonery-cartridge". Why this query returns an empty result? If I try to make inner join sql manually it works well as on the screenshot below:

I think that your queries are not equivalent. The SQL output from laravel does not join tables in it's FROM clause, but in your manually constructed SQL statement you do a lot of inner joins in your FROM clause and on the resulting table you perform your operations, which is not true for the former.
Try the following
DB::table('products')
->join('category_product', 'category_product.product_id', '=', 'products.id')
->join('categories', 'category_product.category_id', '=', 'categories.id')
->whereRaw('products.name LIKE %can% AND categories.slug = "tonery-cartridge"')
->select('products.name', 'categories.slug')
->orderBy('created_at','DESC')
->take(10)
->get()
If you want to avoid using whereRaw, you can try the following.
DB::table('products')
->join('category_product', 'category_product.product_id', '=', 'products.id')
->join('categories', 'category_product.category_id', '=', 'categories.id')
->where([
['products.name, 'LIKE', '%' . $value . '%'],
['categories.slug', '=', 'tonery-cartridge']])
->select('products.name', 'categories.slug')
->orderBy('created_at','DESC')
->take(10)
->get()
HTH

This could be one of the solutions
$category = Category::where( 'slug', 'tonery-cartridge' )->first();
$products = $category->products()
->where('name', 'LIKE', "%{$value}%")
->with('manufacturer')
->with('sm_image')
->latest()
->take(10)
->get();

Related

Yii2: how to use subquery with ActiveRecord?

I want to create a find function to use then in a GridView widget My I don't know how to use a subquery.
This is the simple version of the PostgreSQL query that I have:
SELECT color
FROM cars
LEFT JOIN (
SELECT name
FROM companies
)
Here is what I a trying and doesn't work:
$query = Cars::find()
->select([
'color' => '
SELECT name // Problem here.
FROM companies // Problem here.
',
]);
Your expected query is not what you are trying to do. You can add a custom subquery as
$query = Cars::find()
->select([
'(SELECT name FROM companies) AS xxx'
]);
But if you want to add a field from joined table to the grid, then you should have a relation defined and then you can easily add such a column to your grid. See https://www.yiiframework.com/doc/guide/2.0/en/db-active-record#relational-data
You can use instance of ActiveQuery in leftJoin() method like this:
$subQuery = Companies::find()
->select('name', 'id'); //I've added ID to show how to write on condition
$query = Cars::find()
->select('color')
->leftJoin(
['alias' => $subQuery],
'alias.id = cars.company_id'
);
See documentation for more details about leftJoin() and join() methods.
$query = Cars::find()
->select(['cars.color','companies.name'])
->leftJoin('companies', 'cars.company_id = companies.id');

Laravel query with where and where

I've trying to basically do two SQL requests into one laravel array.
These are my SQL
SELECT * FROM `transactions` WHERE `plan` LIKE '1050' ORDER BY `updated_at` DESC
SELECT * FROM `transactions` WHERE `user` LIKE '1050' ORDER BY `updated_at` DESC
I want to have all transaction that have "plan" == "1050" AND all transactions that have "user" == "1050" in one variable.
This is not working for me:
$ct=transactions::where('user',$user->id)
->orWhere('plan', $user->id)
->orderby('created_at',"asc")->get();
The context agnostic way to combine the results of two union compatible queries (such as yours) would be:
$result = transactions::where('plan', 'LIKE', $user->id)->orderBy('updated_at', 'DESC')
->union(
transactions::where('user', 'LIKE', $user->id)
->orderBy('updated_at', 'DESC')
)
->get();
This of course means that the results are ordered by plan then user. You can sort them by updated_at globally using the below function on the result:
$result = $result->sortBy('updated_at', 'DESC');
There's also a way to do it on the query level but I don't see much benefit since you're getting all the data anyway.
The above query should be functionally equivalent to:
$result = transactions::orWhere('plan', 'LIKE', $user->id)
->orWhere('user', 'LIKE', $user->id)
->orderBy('updated_at', 'DESC')
->get();
This will have the same results but in a different order than the union.

Laravel Query Builder Statement return no result, but sql statement does

Laravel Query Builder
$data = CustomerPrepaid
::join('pos_sales', 'customer_prepaid.customer_id', '=', 'pos_sales.customer_id')
->join('pos_sales_product', 'pos_sales.pos_sales_code', '=', 'pos_sales_product.pos_sales_code')
->where('pos_sales_product.product_id', 'customer_prepaid.product_id')
->select('customer_prepaid.customer_id', 'customer_prepaid.created_at',
'pos_sales_product.pos_sales_product_code as reference_no',
'customer_prepaid.product_id', 'customer_prepaid.balance',
'last_used', 'expiry_date', 'customer_prepaid.amount as price')
->offset(($page-1)*$limit)->limit($limit)->get();
SQL
SELECT customer_prepaid.customer_id, customer_prepaid.created_at as purchase_date,
pos_sales_product.pos_sales_product_code as reference_no, customer_prepaid.product_id,
customer_prepaid.balance, customer_prepaid.amount*customer_prepaid.balance as value,
last_used, expiry_date, customer_prepaid.amount as price,
customer_prepaid.amount*customer_prepaid.balance as total
FROM customer_prepaid
JOIN pos_sales ON customer_prepaid.customer_id = pos_sales.customer_id
JOIN pos_sales_product ON pos_sales.pos_sales_code = pos_sales_product.pos_sales_code
WHERE pos_sales_product.product_id = customer_prepaid.product_id
The resulting SQL executed on the server returns the right result, but I get no eloquent result, why might that be?
Oh gosh, took me forever to realize you misused ->where.
Change your ->where to ->whereColumn:
$data = CustomerPrepaid
::join('pos_sales', 'customer_prepaid.customer_id', '=', 'pos_sales.customer_id')
->join('pos_sales_product', 'pos_sales.pos_sales_code', '=', 'pos_sales_product.pos_sales_code')
->whereColumn('pos_sales_product.product_id', 'customer_prepaid.product_id')
->select(
'customer_prepaid.customer_id',
'customer_prepaid.created_at',
'pos_sales_product.pos_sales_product_code as reference_no',
'customer_prepaid.product_id', 'customer_prepaid.balance',
'last_used', 'expiry_date', 'customer_prepaid.amount as price'
)
->offset(($page-1)*$limit)
->limit($limit)
->get();
You have to use whereColumn instead of where to make column comparison. Else it's expecting a third parameter value to be set.
Check the documentation on how to use whereColumn: https://laravel.com/docs/5.5/queries#where-clauses

How to use 'Where Not In' in Laravel 5.4?

I'm trying to create a query where I get data from a table and I use INNER JOIN and Where Not In, I was able to adapt the INNER JOIN part, but in 'WHERE NOT IN' I tried using 'WhereNotIn' from Laravel 5.4. But it returns the error: Invalid argument supplied for foreach()
SELECT
em.erp_mlbid AS category_id
FROM
erp_product AS ep
INNER JOIN
erp_product_category AS epc ON epc.erp_productid = ep.erp_productid
INNER JOIN
erp_mlbcategory_erpcategory AS emc ON emc.erp_categoryid = epc.erp_categoryid
INNER JOIN
erp_mlb_category AS em ON em.erp_mcid = emc.erp_mlbcategoryid
WHERE
ep.erp_productid NOT IN (
SELECT
epm.erp_productid
FROM
erp_product_to_mlb AS epm
)
AND ep.erp_quantity > 0
AND ep.erp_status > 0
LIMIT
10,10
So I created this in my application:
$categoria = DB::table('erp_product')
->join('erp_product_category','erp_product_category.erp_productid', '=', 'erp_product.erp_productid')
->join('erp_mlbcategory_erpcategory', 'erp_mlbcategory_erpcategory.erp_categoryid', '=','erp_product_category.erp_categoryid')
->join('erp_mlb_category', 'erp_mlb_category.erp_mcid', '=', 'erp_mlbcategory_erpcategory.erp_mlbcategoryid')
->select('erp_mlb_category.erp_mlbid')
->whereNotIn('erp_product.erp_productid', function($query){
$query->select('erp_productid')
->from('erp_product')
->where('erp_productid', '=', 'erp_product_category.erp_productid');
})
->get();
Any suggestion?
This lines of code is wrong:
->whereNotIn('erp_product.erp_productid', function($query){
$query->select('erp_productid')
->from('erp_product')
->where('erp_productid', '=', 'erp_product_category.erp_productid');
})
remove this line ->where('erp_productid', '=', 'erp_product_category.erp_productid') cause there is not join here.
you can't say ->whereNotIn('erp_product.erp_productid' and $query->select('erp_productid')->from('erp_product') in the same order whereNotIn to check the value in the first_column not exists in the second_column not in same first_column.
So, clear this line ->where('erp_productid', '=', 'erp_product_category.erp_productid') and check the right name to put in $query->select('right_column_name')->from('right_table_name').
$ids= DB::table('erp_product')->pluck('erp_productid')
$categoria = DB::table('erp_product')
->join('erp_product_category','erp_product_category.erp_productid', '=', 'erp_product.erp_productid')
->join('erp_mlbcategory_erpcategory', 'erp_mlbcategory_erpcategory.erp_categoryid', '=','erp_product_category.erp_categoryid')
->join('erp_mlb_category', 'erp_mlb_category.erp_mcid', '=', 'erp_mlbcategory_erpcategory.erp_mlbcategoryid')
->select('erp_mlb_category.erp_mlbid')
->whereNotIn('erp_product.erp_productid',$ids)
->get();

How can I do this SQL in Query builder laravel

How can I do this SQL in Query builder laravel
select Doctor_id from doctors where Doctor_id NOT IN
(SELECT Doctor_id from report_reviewers WHERE Report_id = 26 )
Try with this
$result = DB::table('doctors')
->whereNotIn('doctor_id', function($q){
$q->from('report_reviewers')
->select('Doctor_id')
->where('Report_id', '=', 26)
})
->select('doctor_id')
->get();
Whenver in doubt, if you know the raw SQL, you can simply do
$query = 'select Doctor_id from doctors ...';
$result = DB::select($query);
Also, all credit goes to this genius How to create a subquery using Laravel Eloquent?
Update
The missing argument comes from the closure you are using
->whereNotIn('doctor_id', function($q,$id){
$q->from('report_reviewers')
->select('Doctor_id')
->where('Report_id',$id);
})
You need to pass the $id variable like this
->whereNotIn('doctor_id', function($q) use ($id) {
$q->from('report_reviewers')
->select('Doctor_id')
->where('Report_id',$id);
})
Try again and see.