I got stuck in this problem I encountered in Laravel query.
Firstly I have this query that i use in order to get transactions
$transactions = Transaction::select(
'customers.member_id as member_id',
DB::raw('
CASE
WHEN transactions.customer_id IS NOT NULL
THEN
customers.name
ELSE
"Tanpa pelanggan"
END AS customer_name
'),
'customers.phone as customer_phone',
DB::raw('COUNT(transactions.id) as sum_qty'),
DB::raw('SUM(final_amount) as sum_amount')
)
->join('outlets', 'outlets.id', '=', 'transactions.outlet_id')
->leftJoin('customers', 'customers.id', '=', 'transactions.customer_id')
->where('outlets.company_id', '=', $companyID)
->where(function ($q) use ($permittedOutlets) {
if (!empty($permittedOutlets)) {
$q->whereIn('transactions.outlet_id', $permittedOutlets);
}
})
->where(function ($query) use ($companyID, $outletID, $startDate, $endDate, $filterData) {
if ($outletID != 0) {
$query->where('transactions.outlet_id', '=', $outletID);
}
if (!empty($startDate) && !empty($endDate)) {
if ($startDate == $endDate) {
$query->whereDate(deviceTimestamp(), '=', $startDate);
} else {
$query->whereDate(deviceTimestamp(), '>=', $startDate)
->whereDate(deviceTimestamp(), '<=', $endDate);
}
}
if ($filterData != "") {
$query->where(function ($q) use ($filterData) {
$q->where('customers.name', 'like', '%' . $filterData . '%')
->orWhere('customers.phone', 'like', '%' . $filterData . '%');
});
}
})
->isSuccessAndVoidedInDifferentDate()
->orderBy($sortField, $sort)
->groupBy('transactions.customer_id');
and for isSuccessAndVoidedInDifferentDate Transactions Model scope
$query->whereRaw('
CASE
WHEN transactions.void_id IS NOT NULL
THEN
EXISTS (
SELECT *
FROM transactions as transactions2
WHERE transactions.void_id = transactions2.id
AND transactions.created_at <> transactions2.created_at
LIMIT 1
)
WHEN transactions.status = \''.self::STATUS_VOID.'\'
THEN
EXISTS (
SELECT *
FROM transactions as transactions2
WHERE transactions.id = transactions2.void_id
AND transactions.created_at <> transactions2.created_at
LIMIT 1
)
ELSE
TRUE
END
');
For Raw MySql Query
SELECT
`customers`.`member_id` AS `member_id`,
CASE
WHEN transactions.customer_id IS NOT NULL THEN customers.name
ELSE 'Tanpa pelanggan'
END AS customer_name,
`customers`.`phone` AS `customer_phone`,
COUNT(transactions.id) AS sum_qty,
SUM(final_amount) AS sum_amount
FROM
`transactions`
INNER JOIN
`outlets` ON `outlets`.`id` = `transactions`.`outlet_id`
LEFT JOIN
`customers` ON `customers`.`id` = `transactions`.`customer_id`
WHERE
`outlets`.`company_id` = 153113
AND (`transactions`.`outlet_id` IN (9164))
AND (DATE(ADDDATE(transactions.device_timestamp,
INTERVAL transactions.timezone HOUR)) >= '2020-02-01'
AND DATE(ADDDATE(transactions.device_timestamp,
INTERVAL transactions.timezone HOUR)) <= '2020-02-29')
AND CASE
WHEN
transactions.void_id IS NOT NULL
THEN
EXISTS( SELECT
*
FROM
transactions AS transactions2
WHERE
transactions.void_id = transactions2.id
AND transactions.created_at <> transactions2.created_at
LIMIT 1)
WHEN
transactions.status = 'void'
THEN
EXISTS( SELECT
*
FROM
transactions AS transactions2
WHERE
transactions.id = transactions2.void_id
AND transactions.created_at <> transactions2.created_at
LIMIT 1)
ELSE TRUE
END
AND `transactions`.`deleted_at` IS NULL
GROUP BY `transactions.customer_id`
ORDER BY `transactions.customer_id` ASC
All transactions have two different status. The status is either success or voided. Transactions types are divided by two categories. First category is transaction with customer and second transaction is without customer. Transaction without customer will be selected as "Tanpa pelanggan" in this case. All transactions here are being grouped by transactions.customer_id.
This question is focusing on
DB::raw('COUNT(transactions.id) as sum_qty'),
at the select part. For simpler understanding the where clauses of company, outlets and date here can be ignored. I am trying to make a condition where the count in the query will return count of success transactions subtracted by count of voided transactions grouped by transactions.customer_id. I am kinda confused about whether I should make subquery with all same where conditions as the main query which is kinda repetitive or any better solution I haven't found.
Example case : With data consists of :
1 voided transaction rest transactions are success
Expected result :
member_id | customer_name | customer_phone| sum_qty | sum_ammount
NULL | Sam | 123xxxx | 1 | 20720
NULL | Tanpa Pelanggan| - | 2 | 28490
Actual result :
member_id | customer_name | customer_phone| sum_qty | sum_ammount
NULL | Sam | 123xxxx | 1 | 20720
NULL | Tanpa Pelanggan| - | 3 | 51800
My question is what's the best way to solve this problem?
Thank you in Advance!
Found the solution !
DB::raw('SUM(CASE WHEN transactions.status != \'void\' THEN 1 ELSE 0 END) - SUM(CASE WHEN transactions.status = \'void\' THEN 1 ELSE 0 END) as sum_qty')
It's to actually use SUM and add CASE condition inside SUM function.