Laravel Eloquent complex Subquery - laravel

I have Following query. I want to rewrite this into Laravel Eloquernt.
SELECT COUNT(*) AS CNT FROM CashTransaction AS A
WHERE A.Flag=0
AND A.IsCancel=0
AND A.Amount-ifnull((
SELECT sum(ifnull(Bills.Amount,0))
FROM CashTransaction AS Bills
WHERE A.ContractID=Bills.ContractID
AND Bills.Flag=2
AND Bills.IsCancel=0),0) > 0
So I could write upto
$commissionDepositCount = CashTransaction::where('Flag', 0)
->where('IsCancel',0)
->where('Amount','>',function($query){
$query->from('CashTransaction')
})
->when($user->Level < 5,function($query) use($user){
$query->where('SenderID',$user->id);
})
->count()
I cannot find how to write subqueries that
A.Amount-ifnull((
SELECT sum(ifnull(Bills.Amount,0))
FROM CashTransaction AS Bills
WHERE A.ContractID=Bills.ContractID
AND Bills.Flag=2
AND Bills.IsCancel=0),0) > 0
Can Anyone help me with this?

Related

Laravel 5.6: is it possible to generate following query by Query Builder or Eloquent?

I have following raw query, is it possible to create this using Laravel Query Builder or Eloquent?
SELECT
SUM(records.per_hub)+SUM(records.additionl_qty) AS qty,
records.cost_price,
(records.cost_price)*(SUM(records.per_hub)+SUM(records.additionl_qty)) AS
total
FROM
(SELECT
COUNT(*) AS per_hub,
CEIL(COUNT(*) * 50 / 100) AS additionl_qty,
m.cost_price
FROM
orders o
LEFT JOIN meals m
ON m.id = o.meal_id
WHERE o.shift_id = 1
AND o.meal_id = 2
AND o.city_id = 283
AND o.restaurant_id = 5
GROUP BY hub_id) records;
Take it as reference.
$sub_query = DB::table('orders as o')
->leftJoin('meals as m','m.id','=','o.meal_id')
->where('o.shift_id','=',1)
->where('o.meal_id','=',2)
->where('o.city_id','=',283)
->where('o.restaurant_id', '=', 5)
->select(DB::raw('COUNT(*) AS per_hub,CEIL(COUNT(*) * 50 / 100) AS additionl_qty,m.cost_price'))
->groupBy('hub_id');
$main_query = DB::table( DB::raw("({$sub_query->toSql()}) as records") )
->select(DB::raw('SUM(records.per_hub)+SUM(records.additionl_qty) AS qty,
records.cost_price,
(records.cost_price)*(SUM(records.per_hub)+SUM(records.additionl_qty)) AS total'))
->get();
Yes its possible to create that using Laravel Query Builder, try looking up the API doc: https://laravel.com/api/5.6/Illuminate/Database/Query/Builder.html#method_addSelect

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();

OrderBy fixed to asc on Eloquent query

I try to convert the following SQL request in an Eloquent query :
SELECT locals.*
FROM prises JOIN locals
ON prises.liaison_id = locals.id
GROUP BY locals.id
ORDER BY COUNT(liaison_id);
And I wrote this :
return $query->select('locals.*')
->from('prises')
->join('locals', function($join) {
$join->on('prises.liaison_id', '=', 'locals.id');
})
->orderBy(DB::raw('count(prises.liaison_id)', 'DESC'))
->groupBy('locals.id');
On my php page, it works, but this query is running :
select "locals".* from "prises"
inner join "locals" on "prises"."liaison_id" = "locals"."id"
group by "locals"."id"
order by count(prises.liaison_id) asc limit 100 offset 0
My Asc/Desc is fixed, and I don't know why. Is using DB::raw that block me ?
Thanks in advance.

Converting a raw query to Laravel query builder

I have the following MySQL query which fetches a list of the last 9 authors to write a post and lists them in order of the date of the last post they wrote.
It's working properly but I'd like to re-write it using the Laravel Query Builder. Here is the query at the moment:
$authors = DB::select("
SELECT
`a`.`id`,
`a`.`name`,
`a`.`avatar`,
`a`.`slug` AS `author_slug`,
`p`.`subheading`,
`p`.`title`,
`p`.`slug` AS `post_slug`,
`p`.`summary`,
`p`.`published_at`
FROM
`authors` AS `a`
JOIN
`posts` AS `p`
ON `p`.`id` =
(
SELECT `p2`.`id`
FROM `posts` AS `p2`
WHERE `p2`.`author_id` = `a`.`id`
ORDER BY `p2`.`published_at` DESC
LIMIT 1
)
WHERE
`a`.`online` = 1
ORDER BY
`published_at` DESC
LIMIT 9
");
I understand the basics of using the query builder, but there doesn't appear to be anything in the Laravel docs that allows for me to JOIN a table ON a SELECT.
Can anyone suggest a way that I can write this query using the Laravel Query builder, or perhaps suggest a way that I can rewrite this query to make it easier to structure with the query builder?
Try to do like this
$data = DB::table('authors')
->select(
'a.id',
'a.name',
'a.avatar',
'a.slug AS author_slug',
'p.subheading',
'p.title',
'p.slug AS post_slug',
'p.summary',
p.published_at')
->from('authors AS a')
->join('posts AS p', 'p.id', '=', DB::raw("
(
SELECT p2.id FROM posts AS p2
WHERE p2.author_id = b.id
ORDER BY p2.published_at
DESC LIMIT 1
)"))
->where('a.online', 1)
->limit(9)
->orderBy('p.published_at', 'desc')
->get();

Eloquent query by aggregated relation

I would like to make a query by an aggregated value from the model relations.
As example I should get only Posts which has the last comment between two dates.
SELECT posts.*, MAX(comments.created_at)
as max FROM posts
JOIN comments ON (comments.post_id = posts.id)
GROUP BY posts.id HAVING max > '2014-01-01 00:00:00' AND max < '2014-02-01 00:00:00'
Instead of joins use builtin methods:
// Assuming you have relations setup
Post::whereHas('comments', function ($q) use ($from, $till) {
$q->groupBy('post_id')
->havingRaw("max(created_at) between '{$from}' and '{$till}'");
})->get();
It will produce:
select * from `posts` where
(select count(*) from `comments` where `comments`.`post_id` = `posts`.`id`
group by `post_id`
having max(created_at) between '2014-01-01' and '2014-02-01'
) >= 1 limit 1

Resources