Counting number of joined rows in left join

SqlOracleJoinCountLeft Join

Sql Problem Overview


I'm trying to write an aggregate query in SQL which returns the count of all records joined to a given record in a table; If no records were joined to the given record, then the result for that record should be 0:

Data

My database looks like this (I'm not able to change the structure, unfortunately):

MESSAGE
----------------------------------------------
MESSAGEID   SENDER        SUBJECT
----------------------------------------------
1           Tim           Rabbit of Caerbannog
2           Bridgekeeper  Bridge of Death

MESSAGEPART
----------------------------------------------
MESSAGEID   PARTNO        CONTENT
----------------------------------------------
1           0             (BLOB)
1           1             (BLOB)
3           0             (BLOB)

(MESSAGEPART has a composite PRIMARY KEY("MESSAGEID", "PARTNO"))

Desired output

Given the data above I should get something like this:

MESSAGEID   COUNT(*)
-----------------------------------------------
1           2
2           0

It seems obvious that I need to do a left join on the MESSAGE table, but how do I return a count of 0 for rows where the joined columns from MESSAGEPART are NULL? I've tried the following:

Logic

I've tried

SELECT m.MESSAGEID, COUNT(*) FROM MESSAGE m
LEFT JOIN MESSAGEPART mp ON mp.MESSAGEID = m.MESSAGEID
GROUP BY m.MESSAGEID;

However, this returns

MESSAGEID   COUNT(*)
-----------------------------------------------
1           2
2           1

I've also tried

SELECT mp.MESSAGEID, COUNT(*) FROM MESSAGE m
LEFT JOIN MESSAGEPART mp ON mp.MESSAGEID = m.MESSAGEID
GROUP BY mp.MESSAGEID;

but this returns

MESSAGEID   COUNT(*)
-----------------------------------------------
1           2
            1

What am I doing wrong here?

Sql Solutions


Solution 1 - Sql

How about something like this:

SELECT m.MESSAGEID, sum((case when mp.messageid is not null then 1 else 0 end)) FROM MESSAGE m
LEFT JOIN MESSAGEPART mp ON mp.MESSAGEID = m.MESSAGEID
GROUP BY m.MESSAGEID;

The COUNT() function will count every row, even if it has null. Using SUM() and CASE, you can count only non-null values.

EDIT: A simpler version taken from the top comment:

SELECT m.MESSAGEID, COUNT(mp.MESSAGEID) FROM MESSAGE m
LEFT JOIN MESSAGEPART mp ON mp.MESSAGEID = m.MESSAGEID
GROUP BY m.MESSAGEID;

Hope that helps.

Solution 2 - Sql

You first want to count in your messaepart table before joining, i think. Try this:

   SELECT m.MessageId
        , COALESCE(c, 0) as myCount
     FROM MESSAGE m
LEFT JOIN (SELECT MESSAGEID
                , count(*) c 
             FROM MESSAGEPART 
            GROUP BY MESSAGEID) mp
       ON mp.MESSAGEID = m.MESSAGEID

Solution 3 - Sql

Don't forget to use DISTINCT in case you will LEFT JOIN more than one table:

SELECT m.MESSAGEID, COUNT(DISTINCT mp.MESSAGEID) FROM MESSAGE m
LEFT JOIN MESSAGEPART mp ON mp.MESSAGEID = m.MESSAGEID
GROUP BY m.MESSAGEID;

Solution 4 - Sql

Return one number as a total of the matching elements between two tables, based on matching columns

In my case, I needed one total number returned for the number/count of matching items from a particular column and from two different tables.

For example, I have two separate tables that each have a PhoneNumber column. Between those two tables, I want to know how many from that column match.

Reference: https://www.guru99.com/joins.html

Using the same tables name above, it would look like this:

SELECT COUNT(DISTINCT m.MESSAGEID) AS COUNT FROM MESSAGE m, MESSAGEPART mp
where mp.MESSAGEID = m.MESSAGEID;

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionerrantlinguistView Question on Stackoverflow
Solution 1 - SqlMark J. BobakView Answer on Stackoverflow
Solution 2 - SqloerkelensView Answer on Stackoverflow
Solution 3 - SqlMikeView Answer on Stackoverflow
Solution 4 - SqlAmiriView Answer on Stackoverflow