Laravel Eloquent with two “WHERE NOT IN” in subquery - mysql

I have this query that I am having trouble to write query in laravel eloquent ORM.
Appreciate if someone can help.
Here is SQL Expression:
SELECT DISTINCT cust, cust_no FROM delivery_sap
WHERE cust NOT IN ( SELECT cust_name FROM customer)
AND cust_no NOT IN ( SELECT cust_code FROM customer)

Instead of executing 3 different queries you can use like shown below,
DB::table('delivery_sap')
->whereNotIn('cust', function ($query) {
$query->select('cust_name')->from('customer');
})
->whereNotIn('cust_no', function ($query) {
$query->select('cust_code')->from('customer');
})
->select('cust', 'cust_no')
->distinct('cust')
->get();
This code will give the exact same query which is asked in the question,
to check the query, use following code
DB::table('delivery_sap')
->whereNotIn('cust', function ($query) {
$query->select('cust_name')->from('customer');
})
->whereNotIn('cust_no', function ($query) {
$query->select('cust_code')->from('customer');
})
->select('cust', 'cust_no')
->distinct('cust')
->toSql();
Output will be,
select distinct `cust`, `cust_no` from `delivery_sap`
where `cust` not in (select `cust_name` from `customer`)
and `cust_no` not in (select `cust_code` from `customer`)

Try Something like this:
DB::table('delivery_sap')
->whereNotIn('cust', DB::table('customer')->pluck('cust'))
->whereNotIn('cust_no', DB::table('customer')->pluck('cust_no'))
->select('cust', 'cust_no')
->groupBy('cust', 'cust_no')
->get();

I corrected the code below pluck('cust') to pluck('cust_name') and
pluck('cust_no') to pluck('cust_code') and it works
DB::table('delivery_sap')
->whereNotIn('cust', DB::table('customer')->pluck('cust_name'))
->whereNotIn('cust_no', DB::table('customer')->pluck('cust_code'))
->select('cust', 'cust_no')
->groupBy('cust', 'cust_no')
->get();

You could use exists or left join for better performance instead of sub queries on same table like in existing solution, there is no need for these 2 extra sub queries
SELECT DISTINCT cust, cust_no
FROM delivery_sap d
WHERE EXISTS (
SELECT 1
FROM delivery_sap
WHERE cust_name = d.cust OR cust_code = d.cust
)
OR
SELECT DISTINCT d.cust, d.cust_no
FROM delivery_sap d
LEFT JOIN delivery_sap d1 ON d.cust = d1.cust_name OR d.cust = d1.cust_code
WHERE d1.cust IS NULL
DB::table('delivery_sap as d')
->leftJoin('delivery_sap as d1', function ($join) {
$join->on('d.cust','=','d1.cust_name')
->orWhere('d.cust', '=', 'd1.cust_code');
})
->whereNull('d1.cust')
->select('cust', 'cust_no')
->distinct()
->get();

Related

raw SQL to laravel query builder

How do you convert this raw sql builder to laravel DB Builder
SELECT *
FROM `applications`
WHERE EXISTS (SELECT *
FROM `applicants`
INNER JOIN `applicant_application`
ON `applicants`.`id` =
`applicant_application`.`applicant_id`
WHERE `applications`.`id` =
`applicant_application`.`application_id`
AND `user_id` = 18)
ORDER BY `created_at` DESC
LIMIT 20
This is what I've tried but doesn't seem to work
DB::table('applications as apt')
->whereExists( function ($q) {
$q->from('applicants as app')
->join('applicant_application as aa', 'app.id', '=', 'aa.applicant_id')
->where('apt.id', '=', 'aa.application_id')
->where('app.user_id', '=', 18);
})->orderBy('created_at', 'DESC')->paginate(10);
Would appreciate any help
Because apt.id and aa.application_id are two columns from diff tables, and you are using where to compare the apt.id with string 'aa.application_id'.
You need to use whereColumn to compare two different columns:
->whereColumn('apt.id', '=', 'aa.application_id')

Laravel select is not working with subquery

I was trying to write laravel function to execute query given below. But i am not getting any result. Please help..
Here is my query
SELECT leads_followup_status_list.followup_status_name, COUNT(FUP.followup_status) FROM leads_enquiry_details LEFT JOIN (SELECT max(followup_id) as FID,leads_enquiry_details_enquiry_id as LID,leads_followup_details.followup_comment,followup_date,followup_status from leads_followup_details WHERE leads_followup_details.followup_deleted=1 GROUP by LID )fup on leads_enquiry_details.enquiry_id=fup.LID JOIN leads_followup_status_list on leads_followup_status_list.followup_status_id =FUP.followup_status where leads_enquiry_details.enquiry_deleted=1 and leads_enquiry_details.enquiry_status=1 GROUP by FUP.followup_status
This is my function
public function getFollowupStatusCount($parametr=null){
$status_counts = LeadsDetails::where('enquiry_deleted', '=', 1)
->where('enquiry_status', 1)
->leftjoin(DB::raw('(SELECT max(followup_id) as FID,leads_enquiry_details_enquiry_id as LID,
leads_followup_details.followup_comment,
followup_date,followup_status from leads_followup_details GROUP by LID )
FUP'),
function($leftjoin)
{
$leftjoin->on('leads_enquiry_details.enquiry_id', '=', 'fup.LID');
})
->leftjoin('leads_followup_status_list.followup_status_id','leads_followup_status_list','fup.followup_status')
->select('COUNT(FUP.followup_status) as count', 'leads_followup_status_list.followup_status_name as status',
'leads_followup_status_list.followup_status_color_code as color')
->groupBy('followup_status');
return $status_counts;
}
Ok so I've noticed 2 problems. First, you miss ->get() at the end of you request. Second, your parameters order is wrong on second leftJoin. Should be:
->leftJoin('leads_followup_status_list',
'leads_followup_status_list.followup_status_id', '=', 'fup.followup_status')
Should work after these fixes.
Thank you very much #Pavel Lint, There were one mistake too . I should have used select( DB::raw('count(FUP.followup_status) as count'),' instead of count..

how to translate this mysql code in laravel

I get 3 tables in my database. I want to know how to translate this mysql query in laravel. Here is the code:
SELECT item.id, item.libelle, entre.item_id, entre.total AS etotal, entre.prix_unitaire AS eprix, sortie.total AS stotal, sortie.prix_unitaire AS sprix, (entre.total - sortie.total) AS restant
FROM (
SELECT id, libelle
FROM items
WHERE EXISTS (
SELECT *
FROM entrees
WHERE items.id = entrees.item_id
AND date_entree = '23-10-2019'
)
) item
LEFT JOIN (
SELECT item_id, prix_unitaire, sum(total) total
FROM entrees
WHERE date_entree = '23-10-2019'
GROUP BY item_id
) entre ON item.id = entre.item_id
LEFT JOIN (
SELECT item_id, prix_unitaire, sum(total) total
FROM sorties
GROUP BY item_id
) sortie ON entre.item_id = sortie.item_id;
For table entrees enter image description here
For table items enter image description here
For table sortiesenter image description here
So please help me. And if possible explain me the query cause honestly I found it on another forum
First let's break down your query into all the subqueries and then write them all together.
Subquery 1
SELECT id, libelle
FROM items
WHERE EXISTS (
SELECT *
FROM entrees
WHERE items.id = entrees.item_id
AND date_entree = '23-10-2019'
)
Translated to Query Builder:
$subquery1 = DB::table('items')
->select('id', 'libelle')
->whereExists(function ($query) {
$query->from('entrees')
->whereColumn('items.id', 'entrees.item_id')
->where('date_entree', '23-10-2019');
});
// You can verify this by dumping $subquery1->toSql() in the console.
Subquery 2
SELECT item_id, prix_unitaire, sum(total) total
FROM entrees
WHERE date_entree = '23-10-2019'
GROUP BY item_id
Translated to Query Builder:
$subquery2 = DB::table('entrees')
->select('item_id', 'prix_unitaire')
->selectRaw('sum(total) as total')
->where('date_entree', '23-10-2019')
->groupBy('item_id');
// You can verify this by dumping $subquery2->toSql() in the artisan console.
Subquery 3
SELECT item_id, prix_unitaire, sum(total) total
FROM sorties
GROUP BY item_id
Translated to Query Builder:
$subquery3 = DB::table('sorties')
->select('item_id', 'prix_unitaire')
->selectRaw('sum(total) as total')
->groupBy('item_id');
// You can verify this by dumping $subquery3->toSql() in the artisan console.
Now, to put it all together:
$query = DB::table($subquery1, 'item')
->select(
'item.id',
'item.libelle',
'entre.item_id',
'entre.total as etotal',
'entre.prix_unitaire as eprix',
'sortie.total as stotal',
'sotrie.prix_unitaire as sprix'
)
->selectRaw('(entre.total - sortie.total) as restant')
->leftJoinSub($subquery2, 'entre', function ($join) {
$join->on('item.id', '=', 'entre.item_id');
})
->leftJoinSub($subquery3, 'sortie', function ($join) {
$join->on('entre.item_id', '=', 'sortie.item_id');
});
// You can verify this by dumping $query->toSql() in the artisan console.
// To get the results, simply append the ->get() to the $query or do $query->get();
Below is a screen capture of this code being tested in the artisan console. The reason I'm using $db-> instead of DB:: is because I ran the following line before:
$db = DB::connection('mysql');
which makes sure the query is translated to mysql when I use toSql(). Pay it no mind.
Everything I used can be found in the official documentation about queries.

nested queries in laravel

Here is my sql, i am struggling to translate this to laravel 5.8 query builder syntax.
SELECT CC AS CountOfVisits, Count(CC) AS Users
FROM
(
SELECT user_id, count(user_id) AS CC FROM mytable
GROUP BY user_id
) AS CC
GROUP BY CC;
I tried this:
$frequency= DB::connection('mysql2')
->select(DB::raw('CC AS CountOfVisits'), DB::raw('Count(CC) AS Users'))
->from(function($sq)
{
$sq->select(DB::raw('user_id, count(user_id) AS CC FROM '))
->from('mytable')
->groupBy('user_id');
})
->groupBy('CC')
->get();
it errors with
Argument 1 passed to Illuminate\Database\Connection::prepareBindings()
must be of the type array, object given, called in
/var/app/portal/vendor/laravel/framework/src/Illuminate/Database/Connection.php
on line 665
Any help would be great thanks
I think the problem you're having is that the returned connection is expecting string for the full query with additional bindings on the second parameter. You can still build it using illuminate's query builder first if you like, then run the select using the generated string.
$query = DB::query()
->select('CC AS CountOfVisits', DB::raw('count(CC) AS Users'))
->fromSub(function (\Illuminate\Database\Query\Builder $query) {
$query->select('user_id', DB::raw('count(user_id) AS CC '))
->from('mytable')
->groupBy('user_id');
}, 'CC')
->groupBy('CC');
$result = DB::connection()->select($query->toSql());

Invalid parameter number error using DataTables with Laravel

When DataTables tries to get data, it always gets tripped up on this Eloquent query:
$items = Item::select([
DB::raw("images.url AS image"),
'items.id',
'items.sku',
'items.quantity',
DB::raw("IF(items.enabled, 'Yes', 'No') AS enabled")
])
->leftJoin('images', function ($j) {
$j->on('images.imageable_id', '=', 'items.id')
->where('images.imageable_type', '=', 'Item');
})
->leftJoin('order_items', 'items.id', '=', 'order_items.item_id')
->leftJoin('orders', 'orders.id', '=', 'order_items.order_id')
->where('items.store_id', 1)
->whereNull('items.deleted_at')
->whereIn('items.status', ['active', 'submitted'])
->groupBy('items.id');
The query works just fine as is and returns the desired results. However, DataTables tries to transform it into the following which produces the error:
select count(*) as aggregate from (select '1' as row from `items` left join `images` on `images`.`imageable_id` = `items`.`id` and `images`.`imageable_type` = 1 left join `order_items` on `items`.`id` = `order_items`.`item_id` left join `orders` on `orders`.`id` = `order_items`.`order_id` where `items`.`store_id` = 1 and `items`.`deleted_at` is null group by `items`.`id`) AS count_row_table
This produces this error specifically:
SQLSTATE[HY093]: Invalid parameter number
/home/vagrant/Projects/test.dev/vendor/laravel/framework/src/Illuminate/Database/Connection.php#301
When I execute that query directly on the MySQL database, it has no problem. This seems to be happening within Laravel only.
If I remove the ->leftJoin('images', function ($j) {...} part of the query then there is no error, but I need that join for the image.
How to get around this error?
Full error output returned to DataTables over AJAX:
{
"error":{
"type":"Illuminate\\Database\\QueryException",
"message":"SQLSTATE[HY093]: Invalid parameter number (SQL: select count(*) as aggregate from (select '1' as row from `items` left join `images` on `images`.`imageable_id` = `items`.`id` and `images`.`imageable_type` = 1 left join `order_items` on `items`.`id` = `order_items`.`item_id` left join `orders` on `orders`.`id` = `order_items`.`order_id` where `items`.`store_id` = active and `items`.`deleted_at` is null and `items`.`status` in (submitted, ?) group by `items`.`id`) AS count_row_table)",
"file":"\/home\/vagrant\/Projects\/test.dev\/vendor\/laravel\/framework\/src\/Illuminate\/Database\/Connection.php",
"line":625
}
}
I have had a similar issue today, not with DataTables but with a complex query being built using the standalone query builder. The issue was similar to yours with the left join, passing a closure to build a more complex join condition. I was using a where condition after the "on".
The solution was to chain "on" calls:
->leftJoin('images', function ($j) {
$j->on('images.imageable_id', '=', 'items.id')
// note the "on" rather than the "where" and the use of a raw statement
->on('images.imageable_type', '=', DB::raw('Item'));
})
I had this exact issue. The work around is not perfect since it will basically grab all the data twice, but it's the only way I could get it to work.
You have to do a ->get(); before sending it to ->make();. I honestly hope someone finds the right solution but for now:
Temp solution:
$data = DB::table('some_table');
$data->leftJoin('some_other_table', function($join)
{
$join->on('some_table.id', '=', 'some_other_table.id')
->where('some_table.something', '=', 'some_value');
});
$data->get();
return Datatables::of($data)->make();
This is with using the datatables package for Laravel: https://github.com/bllim/laravel4-datatables-package