I have a display table that churns out daily result in the form of mysql. The daily result does not include products that are not making any sales today. How do i read from the table and determine to list all products even if a particular product is not making a sale that particular day but exists on the table on another day.
I researched and understand that using EXIST
on the WHERE
clause works. But i tried but to no avail. I think I just have to include a grouped sub query inside a query but where should i put it. Below is an example of my code
SELECT
transaction.transactionservicetype AS Services,
COUNT(transaction.transactionid) AS Count,
IFNULL (SUM(transaction.transactionamount),'0') AS Amount,
IFNULL (SUM(statement.statementdebit),'0') AS NetCost,
IFNULL((SUM(transaction.transactionamount) - SUM(statement.statementdebit)),'0') as TotalEarning
FROM transaction
RIGHT JOIN statement ON transaction.transactionid = statement.transactionid
WHERE transaction.transactiondate = '2019-04-03' AND transaction.transactionstatus = 'SUCCESS'
GROUP BY `transaction`.transactionservicetype ASC
Instead of displaying the table such as this:
Services Count Amount Netcost Total Earning
Chicken 4 5.30 5.14 -
Beef 3 3.30 3.13 -
I want the result to include products not found on the same day but determine another type of products had existed on the table thus displaying the result as such:
Services Count Amount Netcost Total Earning
Chicken 4 5.30 5.14 -
Beef 3 3.30 3.13 -
Venison 0 0 0 -
Fowl 0 0 0 -
I did not get the correct outcome using anti join and the other results. Scanning thru and using Ultimater's code as an example, this is as close to what i'd like to get from the result using sql query:
(
SELECT
transaction.transactionservicetype AS Services,
COUNT(transaction.transactionid) AS Count,
IFNULL (SUM(transaction.transactionamount),'0') AS Amount,
IFNULL (SUM(statement.statementdebit),'0') AS NetCost,
IFNULL((SUM(transaction.transactionamount) - SUM(statement.statementdebit)),'0') as TotalEarning
FROM
transaction RIGHT JOIN statement
ON
transaction.transactionid = statement.transactionid
WHERE
transaction.transactiondate = '2019-04-03' AND transaction.transactionstatus = 'SUCCESS'
GROUP BY
`transaction`.transactionservicetype ASC
)
UNION
(
SELECT
transactionservicetype AS Services,
'0' AS Count,
'0' AS Amount,
'0' AS NetCost,
'0' AS TotalEarning
FROM
transaction
GROUP BY
transactionservicetype ASC
)
The above sql query got me a bit closer to what I wanted from my outcome. And this is the result:
Services Count Amount Netcost Total Earning
Chicken 4 5.30 5.14 -
Beef 3 3.30 3.13 -
Chicken 0 0 0 -
Beef 0 0 0 -
Venison 0 0 0 -
Fowl 0 0 0 -
I just have to remove the duplicated rows (Chicken, Beef)
how do i fix it using sql query?
Untested but pretty sure you're looking for something like this:
The idea being you'd UNION ALL your current results onto an anti-join to get the remaining results to simulate a FULL JOIN :
(
SELECT
transaction.transactionservicetype AS Services,
COUNT(transaction.transactionid) AS Count,
IFNULL (SUM(transaction.transactionamount),'0') AS Amount,
IFNULL (SUM(statement.statementdebit),'0') AS NetCost,
IFNULL((SUM(transaction.transactionamount) - SUM(statement.statementdebit)),'0') as TotalEarning
FROM
transaction RIGHT JOIN statement
ON
transaction.transactionid = statement.transactionid
WHERE
transaction.transactiondate = '2019-04-03' AND transaction.transactionstatus = 'SUCCESS'
GROUP BY
`transaction`.transactionservicetype ASC
)
UNION ALL
(
SELECT
transaction.transactionservicetype AS Services,
COUNT(transaction.transactionid) AS Count,
IFNULL (SUM(transaction.transactionamount),'0') AS Amount,
'0' AS NetCost,
'0' as TotalEarning
FROM
transaction LEFT JOIN statement
ON
transaction.transactionid = statement.transactionid
WHERE
statement.statementid IS NULL AND transaction.transactiondate = '2019-04-03' AND transaction.transactionstatus = 'SUCCESS'
GROUP BY
`transaction`.transactionservicetype ASC
);
You could also leave off the transaction.transactiondate = '2019-04-03' AND transaction.transactionstatus = 'SUCCESS'
on the anti-join depending on the criteria where you want to grab such "missing" services.
The above also assumes transaction.transactionid
is an existing column and a primary key.
The second part is the anti-join:
SELECT
transaction.transactionservicetype AS Services,
COUNT(transaction.transactionid) AS Count,
IFNULL (SUM(transaction.transactionamount),'0') AS Amount,
'0' AS NetCost,
'0' as TotalEarning
FROM
transaction LEFT JOIN statement
ON
transaction.transactionid = statement.transactionid
WHERE
statement.statementid IS NULL AND transaction.transactiondate = '2019-04-03' AND transaction.transactionstatus = 'SUCCESS'
GROUP BY
`transaction`.transactionservicetype ASC
You should be able to run this by itself and see results such as this:
Services Count Amount Netcost Total Earning
Venison 0 0 0 0
Fowl 0 0 0 0
I wrote the anti-join by changing the RIGHT JOIN to a LEFT JOIN, specifying statement.statementid IS NULL
in the WHERE clause so you don't get any INNER JOIN data you already have from the previous query, and I adjusted the counting logic such as NetCost and TotalEarnings by hard-coding those since there'd be no matches for those in such an anti-join in order to speed up its logic.
Using an anti-join for the purposes of simulating a full join in MySQL is covered in this answer here:
https://stackoverflow.com/a/4796911/466314
An anti-join is a term used in the post I linked to, but not really an official term. The term "anti" here means there needs to be an original join, then you want to do another join but grab the inverse of that join when masked to a full join. This is different from merely combining the results of a LEFT and RIGHT (outer) join with each other because they share the same INNER JOIN data and you'd have redundant results.
A UNION ALL
allows that sort of redundancy. A UNION
by itself removes those duplicates.
If you want to rely upon UNION to remove those duplicates, you can simulate an easier to understand FULL JOIN like so:
(
SELECT
transaction.transactionservicetype AS Services,
COUNT(transaction.transactionid) AS Count,
IFNULL (SUM(transaction.transactionamount),'0') AS Amount,
IFNULL (SUM(statement.statementdebit),'0') AS NetCost,
IFNULL((SUM(transaction.transactionamount) - SUM(statement.statementdebit)),'0') as TotalEarning
FROM
transaction RIGHT JOIN statement
ON
transaction.transactionid = statement.transactionid
WHERE
transaction.transactiondate = '2019-04-03' AND transaction.transactionstatus = 'SUCCESS'
GROUP BY
`transaction`.transactionservicetype ASC
)
UNION
(
SELECT
transaction.transactionservicetype AS Services,
COUNT(transaction.transactionid) AS Count,
IFNULL (SUM(transaction.transactionamount),'0') AS Amount,
IFNULL (SUM(statement.statementdebit),'0') AS NetCost,
IFNULL((SUM(transaction.transactionamount) - SUM(statement.statementdebit)),'0') as TotalEarning
FROM
transaction LEFT JOIN statement
ON
transaction.transactionid = statement.transactionid
WHERE
transaction.transactiondate = '2019-04-03' AND transaction.transactionstatus = 'SUCCESS'
GROUP BY
`transaction`.transactionservicetype ASC
);
All I did was wrote the same original query again but changed the term RIGHT to LEFT, and put them between a UNION to remove duplicates when joining the results together.
Edit:
Here's the latest suggestion: Use the original query, but change from a RIGHT JOIN to a LEFT JOIN, then move the entire WHERE clause to the ON clause.
SELECT
transaction.transactionservicetype AS Services,
COUNT(transaction.transactionid) AS Count,
IFNULL (SUM(transaction.transactionamount),'0') AS Amount,
IFNULL (SUM(statement.statementdebit),'0') AS NetCost,
IFNULL((SUM(transaction.transactionamount) - SUM(statement.statementdebit)),'0') as TotalEarning
FROM
transaction LEFT JOIN statement
ON
transaction.transactionid = statement.transactionid AND
transaction.transactiondate = '2019-04-03' AND
transaction.transactionstatus = 'SUCCESS'
GROUP BY
`transaction`.transactionservicetype ASC
As per the results given to me, we can modify the almost attempt and merely do a subquery on the results, and a group by to get the desired output:
SELECT r.Services as 'Services',SUM(r.Count) as 'Count', SUM(r.Amount) as 'Amount',SUM(r.NetCost) as 'NestCost', SUM(r.TotalEarnings) AS 'TotalEarnings'
FROM
(
SELECT
transaction.transactionservicetype AS Services,
COUNT(transaction.transactionid) AS Count,
IFNULL (SUM(transaction.transactionamount),'0') AS Amount,
IFNULL (SUM(statement.statementdebit),'0') AS NetCost,
IFNULL((SUM(transaction.transactionamount) - SUM(statement.statementdebit)),'0') as TotalEarning
FROM
transaction RIGHT JOIN statement
ON
transaction.transactionid = statement.transactionid
WHERE
transaction.transactiondate = '2019-04-03' AND transaction.transactionstatus = 'SUCCESS'
GROUP BY
`transaction`.transactionservicetype ASC
UNION
SELECT
transactionservicetype AS Services,
'0' AS Count,
'0' AS Amount,
'0' AS NetCost,
'0' AS TotalEarning
FROM
transaction
GROUP BY
transactionservicetype ASC
) r
GROUP BY r.Services;
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.