Kushan
Kushan

Reputation: 5984

MYSQL join query not working as expected

I have basically have two tables:

1) billingcharges : here we store id of a restaurant (restid) , charge id (chargeid), chargetime(timeinmillis when the charge occurred),chargeamount(int amount of the actual charge).charge id is a foreign key to the billingchargedetails table.

2) billingchargedetails: here we store the details of all the possible charges. chargeid(primary key int), chargename (name of the charge), perdaycost (cost per day of the charge)

What i expect:

a summary report of totalamount of charge for each charge for each restaurant.

The current entries inside the tables are:

select * from billingcharges;
+--------+----------+---------------+--------------+
| restid | chargeid | chargetime    | chargeamount |
+--------+----------+---------------+--------------+
|      1 |        1 | 1536363636363 |          700 |
|      2 |        1 | 1536363636363 |          500 |
|      1 |        1 | 1568789654123 |          500 |
+--------+----------+---------------+--------------+

select * from billingchargedetails;

+----------+--------------------+------------------+
| chargeid | chargename         | chargecostperday |
+----------+--------------------+------------------+
|        1 | Base Charge        |               50 |
|        2 | Spotlight Listing  |               50 |
|        3 | Gold Notification  |              500 |
|        4 | Discount (FIRST50) |               18 |
+----------+--------------------+------------------+

A simple join on chargeid ended up not giving me the qty and sum as expected.so i need some form of a left or right outer join, that much i know and tried

I tried a left join as follows:

select restid, B.chargeid, chargename, count(B.chargeid) as qty,
  sum(ifnull(chargeamount,0)) as total 
from billingcharges as B 
left join billingchargedetails as C on B.chargeid=C.chargeid 
group by restid,B.chargeid;

+--------+----------+-------------+-----+-------+
| restid | chargeid | chargename  | qty | total |
+--------+----------+-------------+-----+-------+
|      1 |        1 | Base Charge |   2 |  1200 |
|      2 |        1 | Base Charge |   1 |   500 |
+--------+----------+-------------+-----+-------+

This does work and sums things but there are missing charges for each restaurant. even if they arent present inside the billinghcarges ie the left table, i need it with qty 0 and total 0.

I tried a right join and a random value was selected by mysql from the non existing entries inside the left table as follows:

select restid, B.chargeid, chargename, count(B.chargeid) as qty,
  sum(ifnull(chargeamount,0)) as total 
from billingcharges as B 
right join billingchargedetails as C on B.chargeid=C.chargeid 
group by restid,B.chargeid;

+--------+----------+-------------------+-----+-------+
| restid | chargeid | chargename        | qty | total |
+--------+----------+-------------------+-----+-------+
|   NULL |     NULL | Spotlight Listing |   0 |     0 |
|      1 |        1 | Base Charge       |   2 |  1200 |
|      2 |        1 | Base Charge       |   1 |   500 |
+--------+----------+-------------------+-----+-------+

The expected output is something like:

 restid chargeid  chargename   qty totalamount
  1        1      Base Charge   2   1200
  1        2      Spotlight     0   0
  1        3      Gold          0   0
  1        4      Discount      0   0
  2        1      Base Charge   1   500
  2        2      Spotlight     0   0
  2        3      Gold          0   0
  2        4      Discount      0   0
  'same as above expected for each restid in billingcharges'

Upvotes: 0

Views: 47

Answers (1)

Bill Karwin
Bill Karwin

Reputation: 562981

Before you can do the outer join, you need to generate the cross-product of restaurants to charge types.

Something like the following (but I have not tested it):

SELECT R.restid, D.chargename, COUNT(B.chargeid) AS qty,
  SUM(IFNULL(B.chargeamount, 0)) AS total
FROM (SELECT DISTINCT restid FROM billingcharges) AS R
CROSS JOIN billingchargedetails AS D
LEFT JOIN billingcharges AS B ON R.restid=B.restid AND D.chargeid=B.chargeid
GROUP BY R.restid, D.chargename;

In this example, the cross-product of R and D is every restaurant crossed with every charge type.

Of course not all of those charges exist for every restaurant. So the outer join to billingcharges finds those rows that do exist for each respective combination of restaurant & charge type.

Upvotes: 1

Related Questions