user_m
user_m

Reputation: 53

Get count of rows from joining 2 tables

I have 2 tables:

Table1: users

id name faculty_id level_id
1 john 1 1
2 mark 1 1
3 sam 1 2

Table 2: subjects

id title faculty_id
1 physics 1
2 chemistry 1
3 english 2

SQL query:

SELECT count(subjects.id) FROM users INNER JOIN subjects ON users.faculty_id = subjects.faculty_id WHERE users.level_id = 1

I'm trying to get count of subjects where users.level_id = 1, Which should be 2 in this case physics and chemistry.

But it's returning more than 2.

Why is that and how to get only 2?

Upvotes: 2

Views: 2041

Answers (5)

Thorsten Kettner
Thorsten Kettner

Reputation: 95101

The two tables are not directly related as none is parent to the other. The faculty table is parent to both tables and this is what relates the two tables indirectly.

When joining the faculties' students with the faculties' subjects per faculty, you get all combinations (john|physics, mark|physics, sam|physics, john|chemistry, mark||chemistry, ...). Whether John really has the subject Physics cannot even be gathered from the database. We see that John studies a faculty containing the subjects Physics and Chemistry, but does every student have every subject belonging to their faculty? You probably know but we don't. That shows that in order to write proper queries, one should know their database :-)

Now you are joining the tables and get all students per faculty multiplied with all subjects per faculty. You limit this to level_id = 1, which gets you 2 students x 2 subjects = 4. You could use COUNT(*) for this, because you are counting rows. By applying COUNT(subjects.id) instead you are only counting rows for which the subject ID is not null, but that is true for all rows, because all four combined rows have either subject ID 1 (Physics) or 2 (Chemistry). Counting something that cannot be null makes no sense, except for counting distinct, as has already been suggested. You can COUNT(DISTINCT subjects.id) to get the distinct number of subjects matching yur conditions.

This, however, has two drawbacks. First, the query doesn't clearly show your intention. Why do you join all students with all subjects, when your are not really interested in the (four) combinations? Secondly, you are building an unnecessary intermediate result (four rows in your small example) that must be searched for duplicates, so these can be removed from the counting. That means more memory consumed and more work for the DBMS.

What you want to count is subjects. So select from the subjects table. Your condition is that a student exists with level 1 for the same faculty. Conditions belong in the WHERE clause. Use EXISTS as Gordon suggests in his answer or use IN which is slightly shorter to write and may hence be considered a tad more readable (but that boils down to personal preference, as EXISTS and IN express exactly the same thing here).

select count(*)
from subjects
where faculty_id in (select faculty_id from users where level_id = 1);

Upvotes: 1

Sanyogita Waykar
Sanyogita Waykar

Reputation: 88

You want to count level_id and you have mentioned subject_id in the code. I would suggest first join two tables.

SELECT users.name, users.level_id, 
subjects.title 
FROM users 
INNER JOIN subjects ON 
users.faculty_id = subjects.faculty_id  as new_table 

After joining the table u can get the count.

SELECT level_id, COUNT(level_id) 
FROM new_table 
GROUP BY level_id 
WHERE level_id = 1 

(You have not mentioned group by in your code.)

Upvotes: 0

Gordon Linoff
Gordon Linoff

Reputation: 1271241

I would recommend exists:

SELECT COUNT(*) 
FROM subjects s
WHERE EXISTS (SELECT 1
              FROM users u
              WHERE u.faculty_id = s.faculty_id AND
                    u.level_id = 1
             );

This counts subjects where a user exists with a level of 1.

Upvotes: 2

Swapnil Patil
Swapnil Patil

Reputation: 19

You can just add "distinct" before subjects.id

your SQL query like:

SELECT count(distinct subjects.id) FROM users INNER JOIN subjects ON users.faculty_id = subjects.faculty_id WHERE users.level_id = 1

Upvotes: 0

ysth
ysth

Reputation: 98528

You are joining users and subjects on faculty_id; this produces every combination of user and subject rows (2 users and 2 subjects makes 4 combined rows); change your query to SELECT users.*, subjects.* FROM... to see how this works.

count(subjects.id) counts the number of non-null subjects.id values in your results; you can just do count(distinct subjects.id).

Upvotes: 1

Related Questions