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
Related
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')
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..
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.
I am working on some maintaince project where all are sql queries but i want to convert it in to laravel. Here is the below query :-
$members = Member::select('members.id','members.first_name',
'members.surname','members.username','members.password',
'members.email','user_access.active',
DB::raw('SUM( IF (user_access.active = "y", 1, 0) ) as acount'))
->join('user_access','user_access.member_id','=','members.id')
->where('special_access','=','n')
->groupby('user_access.member_id')
->having('acount','>','0')
->orderby('members.id','desc')
->orderby('members.username','ASC')
->orderby('user_access.note','DESC')
->paginate(30);
Its giving me error when i execute the query. below the error in having clause
SQLSTATE[42S22]: Column not found: 1054 Unknown column 'acount' in 'having clause' (SQL: select count(*) as aggregate from `members` inner join `user_access` on `user_access`.`member_id` = `members`.`id` where `special_access` = n group by `user_access`.`member_id` having `acount` > 0)
I guess something like this will help you.
$userAccess = DB::table('user_access')
->where('special_access','=','n')
->where('active','y')
->groupby('member_id');
Member::select([
'members.id',
'members.first_name',
'members.surname',
'members.username',
'members.password',
'members.email',
'user_access.active'
])->joinSub($userAccess, 'user_access', function($join){
$join->on('user_access.member_id', '=', 'members.id');
})->orderby('members.id','desc')
->orderby('members.username','ASC')
->orderBy('user_access.note','asc')
->paginate(30);
OR
$members = Member::select([
'members.id',
'members.first_name',
'members.surname',
'members.username',
'members.password',
'members.email',
'user_access.active'
])->join('user_access', function($join){
$join->on('user_access.member_id', '=', 'members.id')->on('user_access.active', '=', DB::raw('"y"'));
})
->where('special_access','=','n')
->groupby('user_access.member_id')
->orderby('members.id','desc')
->orderby('members.username','ASC')
->orderby('user_access.note','DESC')
->paginate(30);
As apokryfos said in the comments:
The paginator will attempt to get the count of the query and will remove all selects from it when doing so leading to this error.
If you just need records with user_access.active = "y" then you do not need to select them in the first place and then try to filter them out by HAVING
I need to join a table on a already joined table cause the data I need from the other table is also spread in another table. This is my SQL model so far:
Now I need to join the addresses table the joined child table as well cause I need the address of each child as well. My only problem is, how can I join the table addresses based on the childs.address_id?
I have already tried to to this:
INNER JOIN `addresses` AS `addresse_child` ON `childs`.`address_id` = `addresses`.`id`
Sadly not working..
My SQL Query so far (DB::getQueryLog())
SELECT `assignments`.`id` AS `assignment_id`,
`assignments`.`persons` AS `assignment_persons`,
`assignments`.`start_date` AS `assignment_start_date`,
`assignments`.`end_date` AS `assignment_end_date`,
`addresses`.`id` AS `address_id`,
`addresses`.`first_name` AS `address_first_name`,
`addresses`.`last_name` AS `address_last_name`,
`addresses`.`company` AS `address_company`,
`childs`.`id` AS `child_id`,
`childs`.`address_id` AS `child_address_id`,
`childs`.`sibling_id` AS `child_sibling_id`,
`childs`.`height` AS `child_height`,
`childs`.`weight` AS `child_weight`
FROM `assignments`
INNER JOIN `addresses` ON `assignments`.`address_id` = `addresses`.`id`
INNER JOIN `childs` ON `assignments`.`id` = `childs`.`assignment_id`
WHERE `assignments`.`deleted_at` IS NULL
AND `addresses`.`deleted_at` IS NULL
AND `childs`.`deleted_at` IS NULL
My Laravel SQL command:
$assignment_data = DB::table('assignments')
->join('addresses', 'assignments.address_id', '=', 'addresses.id')
->join('childs', 'assignments.id', '=', 'childs.assignment_id')
->select(
'assignments.id as assignment_id',
'assignments.persons as assignment_persons',
'assignments.start_date as assignment_start_date',
'assignments.end_date as assignment_end_date',
'addresses.id as address_id',
'addresses.first_name as address_first_name',
'addresses.last_name as address_last_name',
'addresses.company as address_company',
'childs.id as child_id',
'childs.address_id as child_address_id',
'childs.sibling_id as child_sibling_id',
'childs.height as child_height',
'childs.weight as child_weight'
)
->whereNull('assignments.deleted_at')
->whereNull('addresses.deleted_at')
->whereNull('childs.deleted_at')
->get();
You should be able to do;
SELECT `assignments`.`id` AS `assignment_id`,
`assignments`.`persons` AS `assignment_persons`,
`assignments`.`start_date` AS `assignment_start_date`,
`assignments`.`end_date` AS `assignment_end_date`,
`addresses`.`id` AS `address_id`,
`addresses`.`first_name` AS `address_first_name`,
`addresses`.`last_name` AS `address_last_name`,
`addresses`.`company` AS `address_company`,
`childs`.`id` AS `child_id`,
`childs`.`address_id` AS `child_address_id`,
`childs`.`sibling_id` AS `child_sibling_id`,
`childs`.`height` AS `child_height`,
`childs`.`weight` AS `child_weight`
FROM `assignments`
INNER JOIN `addresses` ON `assignments`.`address_id` = `addresses`.`id`
INNER JOIN `childs` ON `assignments`.`id` = `childs`.`assignment_id` AND
`childs`.`address_id` = `addresses`.`id`
WHERE `assignments`.`deleted_at` IS NULL
AND `addresses`.`deleted_at` IS NULL
AND `childs`.`deleted_at` IS NULL
And in Laravel this can be achieved by doing;
$assignment_data = DB::table('assignments')
->join('addresses', 'assignments.address_id', '=', 'addresses.id')
->join('childs', function($q) {
$q->on('assignments.id', '=', 'childs.assignment_id')
->where('childs.address_id', '=', 'addresses.id');
})
->select(
'assignments.id as assignment_id',
'assignments.persons as assignment_persons',
'assignments.start_date as assignment_start_date',
'assignments.end_date as assignment_end_date',
'addresses.id as address_id',
'addresses.first_name as address_first_name',
'addresses.last_name as address_last_name',
'addresses.company as address_company',
'childs.id as child_id',
'childs.address_id as child_address_id',
'childs.sibling_id as child_sibling_id',
'childs.height as child_height',
'childs.weight as child_weight'
)
->whereNull('assignments.deleted_at')
->whereNull('addresses.deleted_at')
->whereNull('childs.deleted_at')
->get();
However you should note that by doing INNER JOINS you will only get results if there are rows in each table. You maybe better off doing LEFT JOINS instead, depending on how your data is required.