How to do LEFT OUTER JOIN in Laravel raw expression - laravel

This raw query is working well with two commented lines.
$q = DB::table('stock_items')
->selectRaw('stock_parts.title')
->selectRaw('COUNT(*) as qtyAvailable')
->selectRaw('SUM(shipments.item_cost) as totalValue')
//->selectRaw('stock_alerts.minimum AS minimum')
->join('stock_parts', 'stock_items.stock_part_id', '=', 'stock_parts.id')
->join('shipments', 'shipments.id', '=', 'stock_items.shipment_id')
//->leftJoin('stock_alerts', 'stock_alerts.stock_part_id', '=', 'stock_items.stock_part_id')
->whereNull('stock_items.status')
->where('stock_items.current_stock_id', '=', $stockId)
->groupBy('stock_parts.id')
->get();
The commented lines are needed to get information from another table.
In raw SQL I was using LEFT OUTER JOIN and it works.
Uncommenting those lines it shows this error:
SQLSTATE[42000]: Syntax error or access violation: 1055
Expression #4 of SELECT list is not in GROUP BY clause
and contains nonaggregated column 'rdphone-dev.stock_alerts.minimum'
which is not functionally dependent on columns in GROUP BY clause;
this is incompatible with sql_mode=only_full_group_by (SQL: select stock_parts.title, COUNT(*) as qtyAvailable, SUM(shipments.item_cost) as totalValue, stock_alerts.minimum AS minimum from `stock_items` inner join `stock_parts` on `stock_items`.`stock_part_id` = `stock_parts`.`id` inner join `shipments` on `shipments`.`id` = `stock_items`.`shipment_id` left join `stock_alerts` on `stock_alerts`.`stock_part_id` = `stock_items`.`stock_part_id` where `stock_items`.`status` is null and `stock_items`.`current_stock_id` = 1 group by `stock_parts`.`id`)",
What is the correct way to do LEFT OUTER JOIN in Laravel 5.6?

Every field used in the select has to be included in the group by, I added the minimum column in the groupBy.
$q = DB::table('stock_items')
->selectRaw('stock_parts.title')
->selectRaw('COUNT(*) as qtyAvailable')
->selectRaw('SUM(shipments.item_cost) as totalValue')
->selectRaw('stock_alerts.minimum AS minimum')
->join('stock_parts', 'stock_items.stock_part_id', '=', 'stock_parts.id')
->join('shipments', 'shipments.id', '=', 'stock_items.shipment_id')
->leftJoin('stock_alerts', 'stock_alerts.stock_part_id', '=', 'stock_items.stock_part_id')
->whereNull('stock_items.status')
->where('stock_items.current_stock_id', '=', $stockId)
->groupBy('stock_parts.id', 'minimum')
->get();

Related

Laravel Inner Join With Both Null Column Values

I will have to write an inner join with custom SELECT statement in it and one of the conditions required is to get those rows which have matching null values in the columns, I was able to get the relationship in raw sql statment with (a.<col> = b.<col> OR (a.<col> IS NULL AND b.<col> IS NULL)) but I do not know how to write it using Laravel Eloquent. What is the inner join with OR in Laravel Eloquent? I have tried with $join->on('a.<col>', '=', 'b.<col>')->where('a.<col>', '=', DB::raw(NULL))->where('b.<col>', '=', DB::raw(NULL)); but it doesn't give me the expected result.

how to join 3 tables using laravel eloquent?

my table
Code:
function viewPDF()
{
$reports = Report::join('president_report', 'reports.id', '=', 'president_report.report_id')
->join('president_report', 'presidents.id', '=', 'president_report.president_id')->
select('reports.*')->where('president_report.report_id')
->filter()->latest()->get();
$pdf = PDF::loadView('reports.test1', ['reports' => $reports]);
return $pdf->stream('reports.pdf');
}
Error:
SQLSTATE[42000]: Syntax error or access violation: 1066 Not unique
table/alias: 'president_report' (SQL: select * from reports inner
join president_report on reports.id =
president_report.report_id inner join president_report on
presidents.id = president_report.president_id where
president_report.report_id is null order by created_at desc)
Use separate aliases for the two joins with the president_reports table:
function viewPDF() {
$reports = Report::join('president_report pr1', 'reports.id', '=', 'pr1.report_id')
->join('president_report pr2', 'presidents.id', '=', 'pr2.president_id')->
select('reports.*')->where('pr1.report_id')
->filter()->latest()->get();
$pdf = PDF::loadView('reports.test1', ['reports' => $reports]);
return $pdf->stream('reports.pdf');
}
Note that the second join looks suspicious to me, because I don't see where the presidents table is getting included in the join query. But the general solution to use problem is to alias president_report differently for the two joins.

Convert SQL to Laravel Eloquent Statement

I've been working on a few tables where through a rather complex relationship (that I'm trying to clean up, but I still need reports made from the data through my Laravel).
At the moment, I can pull the data using the following SQL query to my MySQL database:
SELECT
customers.id,
customers.customer_name,
SUM(shipments.balance) AS shipmentBalance
FROM customers
LEFT JOIN shipments
ON customers.id = shipments.bill_to
AND balance > (SELECT IFNULL(SUM(payments_distributions.amount),0)
FROM payments_distributions
WHERE payments_distributions.shipment_id = pro_number)
GROUP BY customers.id, customers.customer_name
ORDER BY shipmentBalance DESC
LIMIT 5;
I'm just not sure how to rewrite it properly into the whereRaw or DB::raw statements that Laravel Eloquent requires, as my previous attempts have failed.
Update
Here is the closest solution I have tried:
DB::table('customers')
->select('customers', DB::raw('SUM(shipments.balance) AS shipmentBalance'))
->leftJoin(
DB::raw('
(select shipments
ON customers.id = shipments.bill_to
AND balance > (SELECT IFNULL(SUM(payments_distributions.amount),0)
FROM payments_distributions
WHERE payments_distributions.shipment_id = pro_number)'))
->groupBy('customers.id')
->orderByRaw('shipmentBalance DESC')
->limit(5)
->get();
Update 2
Edit for Dom:
Using everything as it stands with your answer, I get the following response:
SQLSTATE[42S22]: Column not found: 1054 Unknown column '' in 'on clause' (SQL: select customers.id, customers.customer_name,SUM(s.balance) AS shipmentBalance from `customers` left join `shipments` as `s` on `customers`.`id` = `s`.`bill_to` and s.balance > (SELECT IFNULL(SUM(payments_distributions.amount),0) FROM payments_distributions WHERE payments_distributions.shipment_id = s.pro_number) = `` group by `customers`.`id`, `customers`.`customer_name` order by SUM(s.balance) DESC limit 5)
But if I remove this section, it brings up the page and the customers (though in the wrong order as I have removed one of the necessary components:
$join->on(DB::raw('s.balance >
(SELECT IFNULL(SUM(payments_distributions.amount),0)
FROM payments_distributions
WHERE payments_distributions.shipment_id = s.pro_number)
'));
Is there anything I can provide you with to get this specific statement to work with your entire answer?
Use this:
DB::table('customers')
->select('customers.id', 'customers.customer_name', DB::raw('SUM(shipments.balance) AS shipmentBalance'))
->leftJoin('shipments', function($join) {
$join->on('customers.id', 'shipments.bill_to')
->where('balance', '>', function($query) {
$query->selectRaw('IFNULL(SUM(payments_distributions.amount),0)')
->from('payments_distributions')
->where('payments_distributions.shipment_id', DB::raw('pro_number'));
});
})
->groupBy('customers.id', 'customers.customer_name')
->orderByDesc('shipmentBalance')
->limit(5)
->get();
Without the Models containing relationships or being able to test on this specific project, this is the most eloquent way I can think of performing your task.
The benefit of starting with the Customer model is you will have a laravel collection and can paginate as needed. Also review the eloquent docs, they help you understand all the different options. Hope his helps.
P.S. Start by using your model in your controller or wherever you are placing this query with:
use App\Customer
The query
$theQuery = Customer::select(DB::raw('customers.id, customers.customer_name,SUM(s.balance) AS shipmentBalance'))
->leftJoin('shipments as s', function($join)
{
$join->on('customers.id', '=', 's.bill_to');
$join->on(DB::raw('s.balance >
(SELECT IFNULL(SUM(payments_distributions.amount),0)
FROM payments_distributions
WHERE payments_distributions.shipment_id = s.pro_number)
'));
})
->groupBy('customers.id', 'customers.customer_name')
->orderByRaw('SUM(s.balance) DESC')
->limit(5)
->get();

Laravel Left Join Query

I am using laravel 5.3 and I have some left join query with error in laravel query method.
This is my normal query
SELECT bran.branchName,sch.schoolName From m_schoolbranch bran
LEFT JOIN m_students stu ON stu.schoolNo=bran.schoolNo AND stu.branchNo=bran.branchNo
LEFT JOIN m_school sch ON sch.schoolNo=stu.schoolNo where stu.userNo='0000000001';
And this is my new laravel Query
DB::table('m_schoolbranch')
->join('m_students', 'm_schoolbranch.schoolNo', '=', 'm_students.schoolNo')
->join('m_students', 'm_schoolbranch.branchNo', '=', 'm_students.branchNo')
->join('m_school', 'm_schoolbranch.schoolNo', '=', 'm_school.schoolNo')
->select('m_school.schoolName', 'm_schoolbranch.branchName')
->where('m_students.userNo',$userNo)
->get();
In these query I need to match two column in table m_students so I put like this
->join('m_students', 'm_schoolbranch.branchNo', '=', 'm_students.branchNo')
But i show error...
Tables in the query need to have unique names, otherwise the DB has no way of knowing which m_schoolbranch should be used when evaluating m_schoolbranch.schoolNo.
You could use unique table aliases in your join statements but I recommend using multiple conditions on the join. Just like you use in your original SQL query. See here: https://stackoverflow.com/a/20732468/4437888
DB::table('m_schoolbranch')
->join('m_students', function($join)
{
$join->on('m_schoolbranch.schoolNo', '=', 'm_students.schoolNo');
$join->on('m_schoolbranch.branchNo', '=', 'm_students.branchNo');
})
->join('m_school', 'm_schoolbranch.schoolNo', '=', 'm_school.schoolNo')
->select('m_school.schoolName', 'm_schoolbranch.branchName')
->where('m_students.userNo',$userNo)
->get();

Laravel ordering results of a left join

I am trying to replicate the below SQL in Laravels Eloquent query builder.
select a.name, b.note from projects a
left join (select note, project_id from projectnotes order by created_at desc) as b on (b.project_id = a.id)
where projectphase_id = 10 group by a.id;
So far I have:
$projects = Project::leftjoin('projectnotes', function($join)
{
$join->on('projectnotes.project_id', '=', 'projects.id');
})
->where('projectphase_id', '=', '10')
->select(array('projects.*', 'projectnotes.note as note'))
->groupBy('projects.id')
->get()
which works for everything except getting the most recent projectnotes, it just returns the first one entered into the projectnotes table for each project.
I need to get the order by 'created_at' desc into the left join but I don't know how to achieve this.
Any help would be much appreciated.
Your subquery is unnecessary and is just making the entire thing inefficient. To be sure though, make sure this query returns the same results...
SELECT
projects.name,
notes.note
FROM
projects
LEFT JOIN
projectnotes notes on projects.id = notes.project_id
WHERE
projects.projectphase_id = 10
ORDER BY
notes.created_at desc
If it does, that query translated to the query builder looks like this...
$projects = DB::table('projects')
->select('projects.name', 'notes.note')
->join('projectnotes as notes', 'projects.id', '=', 'notes.project_id', 'left')
->where('projects.projectphase_id', '=', '10')
->orderBy('notes.created_at', 'desc')
->get();

Resources