Getting SUM() from multiple tables with conditions - mysql

I am trying to get the due_amount from two tables that is invoices and offline_invoice.
The condition is; status not like 'paid%'. I am working with this query
select
(sum(i.total_amount) + sum(oi.invoice_amount)) - (sum(i.paid_amount) + sum(oi.paid_amount)) due_amount
from
{CI}invoices i
left join
{CI}offline_invoice oi ON oi.customer_id = i.customer_id
where
i.customer_id = ?
and i.status not like 'paid%'
group by i.customer_id
But i don't know how do i use condition on joined table({CI}offline_invoice)? I have to use the same condition(status not like 'paid%') on it.

Just add the and to the ON clause too
left join
{CI}offline_invoice oi ON oi.customer_id = i.customer_id
AND oi.status not like 'paid%'
where
i.customer_id = ?
and i.status not like 'paid%'
However, I'm not sure how this is going to work for you without possible Cartesian impact. Say you have 10 current invoice and 10 and 6 offline invoices. I would do two separate pre-aggregates joined by their customer ID... unless the off-line invoice has the same invoice ID as current (such as archive purposes)
select
CurInvoices.Customer_ID,
CurInvoices.InvBalance + COALESCE( OIInvoices.OIBalance, 0 ) as AllBalanceDue
from
( select i.customer_id,
sum( i.total_amount - i.paid_amount ) as invBalance
from
{CI}invoices i
where
i.customer_id = ?
and i.status not like 'paid%'
group by
i.customer_ID ) as CurInvoices
LEFT JOIN
( select oi.customer_id,
sum( oi.total_amount - oi.paid_amount ) as OIBalance
from
{CI}offline_invoice oi
where
oi.customer_id = ?
and oi.status not like 'paid%'
group by
i.customer_ID ) as OIInvoces
on CurInvoices.Customer_ID = OIInvoices.customer_ID

Related

Is there a method of counting an attribute that is in a GROUP BY clause?

I need have created a select statement to list out all the customers that have been to multiple merchants below.
I want to create another statement to display how many of those customers have been to each merchant.
What is the optimal method of approaching this problem?
Lists out all customers that have been to multiple merchants.
WITH valentinesDayMerchant AS (
SELECT m.MerchantId, m.MerchantGroupId, m.WebsiteName
FROM Merchant m
INNER JOIN OpeningHours oh ON m.MerchantId = oh.MerchantId AND oh.DayOfWeek = 'TUE'
LEFT JOIN devices.DeviceConnectionState AS dcs ON dcs.MerchantId = oh.MerchantId
WHERE MerchantStatus = '-' AND (m.PrinterType IN ('V','O') OR dcs.State = 1 OR dcs.StateTransitionDateTime > '2023-01-23')
)
SELECT DISTINCT ul.UserLoginId, ul.FullName, ul.EmailAddress, ul.Mobile
FROM dbo.UserLogin AS ul
INNER JOIN dbo.Patron AS p ON p.UserLoginId = ul.UserLoginId
INNER JOIN valentinesDayMerchant AS m ON (m.MerchantId = ul.ReferringMerchantId OR m.MerchantId IN (SELECT pml.MerchantId FROM dbo.PatronMerchantLink AS pml WHERE pml.PatronId = p.PatronId AND ISNULL(pml.IsBanned, 0) = 0))
LEFT JOIN (
SELECT mg.MerchantGroupId, mg.MerchantGroupName, groupHost.HostName [GroupHostName]
FROM dbo.MerchantGroup AS mg
INNER JOIN dbo.Merchant AS parent ON parent.MerchantId = mg.ParentMerchantId
INNER JOIN dbo.HttpHostName AS groupHost ON groupHost.MerchantID = parent.MerchantId AND groupHost.Priority = 0
) mGroup ON mGroup.MerchantGroupId = m.MerchantGroupId
LEFT JOIN (
SELECT po.PatronId, MAX(po.OrderDateTime) [LastOrder]
FROM dbo.PatronsOrder AS po
GROUP BY po.PatronId
) orders ON orders.PatronId = p.PatronId
INNER JOIN dbo.HttpHostName AS hhn ON hhn.MerchantID = m.MerchantId AND hhn.Priority = 1
WHERE ul.UserLoginId NOT IN (1,2,100,372) AND ul.UserStatus <> 'D' AND (
ISNULL(orders.LastOrder, '2000-01-01') > '2020-01-01' OR ul.RegistrationDate > '2022-01-01'
)
GROUP BY ul.UserLoginId, ul.FullName, ul.EmailAddress, ul.Mobile
HAVING COUNT(m.MerchantId) > 1
Methods I have tried include adding the merchant name to a group by and displaying the count of the customers, however this does not work as I cannot have anything related to the Merchant in the GROUP BY, or I wouldn't be able to use HAVING clause to identify the customers that have been to multiple merchants. I have also tried selecting all the merchants and counting the distinct customers which doesn't work as it takes into account all the customers, not specifically the customers that have been to multiple merchants only.

HAVING clause not working after server update

We have just made a major upgrade in mysql version from 5.0.51 to 5.6.22 and I have just noticed that one of my queries no longer works properly.
SELECT
p.id AS product_id,
p.code,
p.description,
p.unitofmeasure,
p.costprice,
p.packsize,
vc.rateinpercent,
CASE
WHEN Sum(sales.qty) IS NULL THEN 0
ELSE Sum(sales.qty)
END AS sold,
CASE
WHEN stock.stocklevel IS NULL THEN 0
ELSE stock.stocklevel
END AS stocklevel,
sum(sales.qty) - stock.stocklevel AS diff,
CEIL((sum(sales.qty) - stock.stocklevel) / p.packsize) AS amt
FROM products p
LEFT JOIN
( SELECT
col.product_id,
col.quantity AS qty
FROM customerorderlines col
LEFT JOIN customerorders co
ON co.id = col.customerorder_id
WHERE co.orderdate >= '2014-12-01 00:00:00'
AND co.orderdate <= '2015-02-09 23:59:59'
AND co.location_id IN (1,2,3,7)
) sales
ON sales.product_id = p.id
LEFT JOIN
( SELECT
product_id,
location_id,
Sum(stocklevel) AS stocklevel
FROM stock
WHERE location_id IN (1,2,3,7)
GROUP BY product_id
) stock
ON stock.product_id = p.id
LEFT JOIN vatcodes vc
ON vc.id = p.purchasevatcode_id
WHERE p.supplier_id IN (137)
AND p.currentstatus_v = 1
GROUP BY p.id
HAVING sold > stocklevel
ORDER BY sold DESC
On the old server, the HAVING clause filtered out all results with minuses in, giving a result as follows:
Instead, I am getting the following result on the new server:
Basically, it's filtering out some of the negative results but not all of them. (The datasets are a few days old, which is why the 'Freeze Gel Spray' qty and sold and stock numbers are slightly different)
Hindsight is a wonderful thing but I didn't expect there to by any major changes for queries between server updates so I didn't care to test or check anything. Luckily this one of only two or three queries that use HAVING, so if I have to re-write a couple of queries so be it. Any ideas as to why this is though? If it wasn't working at all, fair enough, but to only be working partially?
Thanks in advance for any insight,
R
I take it you've tried EXPLAIN on the query to find out what it's doing?
Try making the calculated field names unique from the underlying field names so you can be sure what you're filtering on. I've seen some screwy results when the calculated fields have the same names as underlying physical fields.
Having your subqueries return the same format of results (i.e. both summed/grouped) helps to see what's going on.
I haven't tested this query but it may help. If you post the table structures and perhaps some fake data that shows the error, that would help diagnose
SELECT
p.id AS product_id,
p.code,
p.description,
p.unitofmeasure,
p.costprice,
p.packsize,
vc.rateinpercent,
sales.totalSold,
stock.totalStock,
sales.totalSold - stock.totalStock AS diff,
CEIL((sales.totalSold - stock.totalStock) / p.packsize) AS amt
FROM products p
LEFT JOIN (
SELECT
col.product_id,
IFNULL( SUM(col.quantity), 0) AS totalSold
FROM customerorderlines col
LEFT JOIN customerorders co
ON co.id = col.customerorder_id
WHERE co.orderdate >= '2014-12-01 00:00:00'
AND co.orderdate <= '2015-02-09 23:59:59'
AND co.location_id IN (1,2,3,7)
GROUP BY product_id
) sales
ON sales.product_id = p.id
LEFT JOIN (
SELECT
product_id,
IFNULL( SUM(stocklevel), 0) AS totalStock
FROM stock
WHERE location_id IN (1,2,3,7)
GROUP BY product_id
) stock
ON stock.product_id = p.id
LEFT JOIN vatcodes vc
ON vc.id = p.purchasevatcode_id
WHERE p.supplier_id IN (137)
AND p.currentstatus_v = 1
GROUP BY p.id
HAVING totalSold > totalStock
ORDER BY totalSold DESC

How to get nested two values from nested select ? mysql

Query:
SELECT business.bussId,
(select count(invoices.userId) from invoice where invoice.userId = '3000' )
as invoiceCount,
(select SUM(invoices.price) from invoice where invoice.userId = '3000' )
as invoiceprice ,
FROM business WHERE business.bussId=100
How could I get invoice price and invoiceCount using one nested select ?
Move the subquery to the from clause:
SELECT b.bussId, i.invoiceCount, i.invoiceprice
FROM business b cross join
(select count(i.userId) as invoiceCount, SUM(i.price) as invoiceprice
from invoice i
where i.userId = '3000'
) i
WHERE b.bussId = 100;
You can actually write this without the subquery, but your question is specifically about using subqueries.
That form would be:
SELECT b.bussId, count(i.userId) as invoiceCount, SUM(i.price) as invoiceprice
FROM business b left join
invoice i
on i.userId = '3000' and b.bussId = 100
GROUP BY b.bussId;

How can I adjust a JOIN clause so that rows that have columns with NULL values are returned in the result?

How can I adjust this JOIN clause so that rows with a NULL value for the CountLocId or CountNatId columns are returned in the result?
In other words, if there is no match in the local_ads table, I still want the user's result from the nat_ads table to be returned -- and vice-versa.
SELECT u.franchise, CountLocId, TotalPrice, CountNatId, TotalNMoney, (
TotalPrice + TotalNMoney
)TotalRev
FROM users u
LEFT JOIN local_rev lr ON u.user_id = lr.user_id
LEFT JOIN (
SELECT lrr_id, COUNT( lad_id ) CountLocId, SUM( price ) TotalPrice
FROM local_ads
GROUP BY lrr_id
)la ON lr.lrr_id = la.lrr_id
LEFT JOIN nat_rev nr ON u.user_id = nr.user_id
INNER JOIN (
SELECT nrr_id, COUNT( nad_id ) CountNatId, SUM( tmoney ) TotalNMoney
FROM nat_ads
WHERE MONTH = 'April'
GROUP BY nrr_id
)na ON nr.nrr_id = na.nrr_id
WHERE lr.month = 'April'
AND franchise != 'Corporate'
ORDER BY franchise
Thanks in advance for your help!
try the following in where clause while making a left join. This will take all rows from right table with matched condition
eg.
LEFT JOIN local_rev lr ON (u.user_id = lr.user_id) or (u.user_id IS NULL)
Use this template, as it ensures that :
you have only one record per user_id (notice all subquerys have a GROUP BY user_id) so for one record on user table you have one (or none) record on subquery
independent joins (and calculated data) are not messed togeder
-
SELECT u.franchise, one.CountLocId, one.TotalPrice, two.CountNatId, two.TotalNMoney, (COALESCE(one.TotalPrice,0) + COALESCE(two.TotalNMoney,0)) TotalRev
FROM users u
LEFT JOIN (
SELECT x.user_id, sum(xORy.whatever) as TotalPrice, count(xORy.whatever) as CountLocId
FROM x -- where x is local_rev or local_ads I dont know
LEFT JOIN y on x.... = y.... -- where y is local_rev or local_ads I dont know
GROUP BY x.user_id
) as one on u.user_id = one.user_id
LEFT JOIN (
SELECT x.user_id, sum(xORy.whatever) as TotalNMoney, count(xORy.whatever) as CountNatId
FROM x -- where x is nat_rev or nat_ads I dont know
LEFT JOIN y on x.... = y.... -- where y is nat_rev or nat_ads I dont know
GROUP BY x.user_id
) as two on u.user_id = two.user_id

MySQL: "Ignore" if a table row is missing during JOIN

I'm doing a LEFT JOIN on three tables, where the table "time" doesn't necessarily contain any matching rows. But if no matching rows is found in that table, the linked data disappears.
SELECT
w.date AS worker_date,
w.name AS worker_name,
w.address AS worker_address,
w.zip AS worker_zip,
w.place AS worker_place,
w.phone AS worker_phone,
w.email AS worker_email,
w.company AS worker_company,
w.accessibility AS worker_accessibility,
c.date AS client_date,
c.name AS client_name,
c.address AS client_address,
c.zip AS client_zip,
c.place AS client_place,
c.phone AS client_phone,
c.email AS client_email,
c.web AS client_web,
c.contact AS client_contact,
j.date AS job_date,
j.client_id,
j.worker_id,
j.name AS job_name,
j.description AS job_description,
j.type AS job_type,
j.status AS job_status,
j.proof AS job_proof,
j.deadline AS job_deadline,
j.price AS job_price,
j.final_client AS job_final_client,
SUM(t.hours) AS time_hours
FROM
jobs AS j
LEFT JOIN (
workers AS w,
clients AS c,
time AS t
) ON (
w.id = j.worker_id AND
c.id = j.client_id AND
j.id = t.job_id
) GROUP BY
j.id;
How can I make this work?
Thank you in advance.
add
WHERE t.job_id IS NOT NULL before GROUP BY
Try Replace
SUM(t.hours) AS time_hours
to
(SELECT IFNULL(SUM(t.hours),0) FROM time WHERE time.job_id=j.job_id) AS time_hours
And remove the time from the join
I think your basic query is correct (with the join under braces)
Just replace
SUM(t.hours) AS time_hours
with
SUM(if(t.hours is NULL,0,t.hours)) AS time_hours
I am not sure if this is the problem here, but the behavior of commas vs JOINs changed after a certain MySQL version. Try this
...
FROM jobs AS j LEFT JOIN workers AS w ON w.id = j.worker_id
LEFT JOIN clients AS c c.id = j.client_id
LEFT JOIN `time` AS t ON j.id = t.job_id
...
Also modify the SUM with IFNULL as #ajreal suggests.