Strange mysql query output from 3 table join

TableA (Author Table)

author_id
author_name

TableB (Post Table)

post_id
author_id

TableC (Earning Table)

post_id (post id is not unique)
post_earning

I wanted to generate a report consists of per author total earning.

author_id
author_name
total_earning (sum of earnings of all the posts by author)

The SQL Query used:

SELECT
   a.author_id,
   a.author_name,
   sum(post_earning) as total_earnings
FROM TableA a
Inner Join TableB b on b.author_id = a.author_id
Inner Join TableC c on c.post_id = b.post_id
Group By 
   a.author_id,
   a.author_name

The Result I got is this :

ID  user_login  total_earnings
2   Redstar 13.99
7   Redleaf 980.18
10  topnhotnews 80.43
11  zmmishad    39.27
13  rashel  1248.34
14  coolsaint   1.66
16  hotnazmul   9.83
17  rubel   0.14
21  mahfuz1986  1.09
48  ripon   12.96
60  KHK 27.81

The sum of the total earning is actually 2863.22. But if i add all the values of the result table I get 2415. Where is the problem? What I am missing? I am sure SQL Gurus here can help me out.

Here are the 3 tables i am using

http://bit.ly/cNKS6k (TableA.csv)
http://bit.ly/cJxRRN (TableB.csv)
http://bit.ly/bNv9hs (TableC.csv)

Hmmm. Indirectly I suppose you could say JOINs have something with Database Designing, in the sense that when you design your database you need to find out which tables you need and what the relations between those tables are and from there you know which tables to JOIN when.
But it’s not a very direct relation.
I really suggest you read some more tutorials and/or a book as JOINs are not something that can be easily explained through forum posts :slight_smile:

Thanks. It is working great. Thanks again. It was very confusing. Now it got cleared. I will go through “Simply SQL”. I am also very much confused about SQL Joins. I read many free tutorials available but couldn’t understand the basic yet. Does it have anything to do with Database Designing ?

Ah yes, I should have put parentheses around the subqueries:


SELECT
   author_id
 , post_id
FROM
   tableB
WHERE
   author_id NOT IN (
   SELECT
     author_id
   FROM
     tableA
   )


SELECT
   post_id
 , post_earning
FROM
   tableC
WHERE
   post_id NOT IN (
   SELECT
     post_id
   FROM
     tableB
   )

Where is that LIMIT 0,30 coming from by the way, are you running the queries through PHPMyAdmin
Also, are your tables really called tableA, tableB and tableC ?
If not, replace those names in the queries above with the actual names.

Got this error

1064 - You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near ‘SELECT post_id FROM tableB LIMIT 0, 30’ at line 8

I mean at the end of current result

ID user_login total_earnings
2 Redstar 13.99
7 Redleaf 980.18
10 topnhotnews 80.43
11 zmmishad 39.27
13 rashel 1248.34
14 coolsaint 1.66
16 hotnazmul 9.83
17 rubel 0.14
21 mahfuz1986 1.09
48 ripon 12.96
60 KHK 27.81

as a new row ‘others’.

Will it be the correct way to do it? Suggest me please.

Wow, I’m using the leading comma convention and still I manage to mess up the commas :lol:

Here ya go:

SELECT
   a.author_id
 , a.author_name
 , sum(post_earning) as total_earnings
FROM TableA a
Inner Join TableB b on b.author_id = a.author_id
Inner Join TableC c on c.post_id = b.post_id
Group By 
   a.author_id
 , a.author_name
UNION ALL
SELECT
   -1
 , "Others"
 , sum(post_earning) as total_earning
FROM
   tableC
WHERE
   post_id NOT IN (
   SELECT
      post_id
   FROM
      tableB
   )

If you want to get a basic knowledge on MySQL google for “MySQL tutorial” or get a book, like Simply SQL from Rudy Limebeck

SELECT SUM( post_earnings )
FROM TableC
WHERE post_id NOT
IN (

SELECT post_id
FROM TableB
)

returned the rest of the amount i was searching. Thanks man. I will be glad if you give me some noob reference on mysql as i can develop my mysql skill to a minimum level.

[QUOTE=ScallioXTX;4719210]

The first way would include a UNION ALL in the SELECT query and would look something like this:

SELECT
   a.author_id,
   a.author_name,
   sum(post_earning) as total_earnings
FROM TableA a
Inner Join TableB b on b.author_id = a.author_id
Inner Join TableC c on c.post_id = b.post_id
Group By 
   a.author_id,
   a.author_name
UNION ALL
SELECT
   -1,
 , "Others"
 , sum(post_earning) as total_earning
FROM
   tableC
WHERE
   post_id NOT IN (
   SELECT
      post_id
   FROM
      tableB
   )

got an error on this one

#1064 - You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near ' "Others" , sum(post_earning) as total_earning FROM tableC WHERE post_id ' at line 14

What do you mean by “stored as others” ?

There is no absolute correct way to do it, there is only the way you want to do it.

You could either rewrite the query such a way that there is a new row with a name “Others”, or you could make sure that when you delete a row from tableB, the corresponding rows in tableC are removed as well.
That also holds for tableA. If you remove an author from there, you should remove the posts from that author from tableB, and the corresponding earnings from tableC.

The first way would include a UNION ALL in the SELECT query and would look something like this:

SELECT
   a.author_id,
   a.author_name,
   sum(post_earning) as total_earnings
FROM TableA a
Inner Join TableB b on b.author_id = a.author_id
Inner Join TableC c on c.post_id = b.post_id
Group By 
   a.author_id,
   a.author_name
UNION ALL
SELECT
   -1,
 , "Others"
 , sum(post_earning) as total_earning
FROM
   tableC
WHERE
   post_id NOT IN (
   SELECT
      post_id
   FROM
      tableB
   )

For the second way, take a look at foreign keys with ON DELETE CASCADE.
That only works if your tables are InnoDB. If they are MyISAM you should add this functionality to your application.

I believe some of the posts were deleted from the post table and they are 59 in total. in that case the earning will not be given to any author and can be stored as others. I am a noob in database design and sql queries. So Please advice.

Yes. The tables are named TableA, TableB, TableC. Yes I am running the query from phpmyadmin.
First code returned this two fields with 0s.

Second code returned 59 rows of result.

Where is the problem? How can I fix it?

Could you please run the following two queries?


SELECT
   author_id
 , post_id
FROM
   tableB
WHERE
   author_id NOT IN
   SELECT
     author_id
   FROM
     tableA

SELECT
   post_id
 , post_earning
FROM
   tableC
WHERE
   post_id NOT IN
   SELECT
     post_id
   FROM
     tableB

If either (or both) of these queries returns something else than an empty set than that’s your problem right there.

Why? Those aren’t the best table names :wink:

What that tells you is that there are records in tableC for which there are no records in tableB
In other words, you either inserted rows in tableC with a post_id that didn’t exist in tableB, or you removed posts from tableB without removing the corresponding rows from tableC.
You need to figure out which of these two is the case and make sure it doesn’t happen again. Adding a foreign key on tableC helps (after you’ve solved the problem).