I'm having problems to get the correct data from a table which holds different types of records, and I want to count how many of each I've got.
This is a simpler schema:
companies:
| id | name |
|----|----------|
| 1 | company1 |
| 2 | company2 |
messages:
| id | type | text | companies_id |
|----|---------|-------|--------------|
| 1 | request | blah | 1 |
| 2 | report | blah! | 1 |
| 3 | request | foo | 2 |
| 4 | request | bar | 2 |
| 5 | report | hi! | 2 |
And a link to the SQL Fiddle:
http://sqlfiddle.com/#!9/e7237f/6
Note that if I only use one join, to get the total of just one message type for any company, it works:
SELECT c.*, COUNT(m1.id) as requests
FROM companies c
LEFT JOIN messages m1 ON m1.companies_id = c.id AND m1.type = 'request'
GROUP BY c.id;
It won't if I try to list the total for all the message types on any company, like I'm doing here:
SELECT c.*, COUNT(m1.id) as requests, COUNT(m2.id) as reports
FROM companies c
LEFT JOIN messages m1 ON m1.companies_id = c.id AND m1.type = 'request'
LEFT JOIN messages m2 ON m2.companies_id = c.id AND m2.type = 'report'
GROUP BY c.id;
What am I doing wrong? I think there must be a way to do it using joins instead of nested queries, which I guess would be pretty slower.
LEFT JOIN
only once. Use case
expressions to do conditional counting
SELECT c.*,
SUM(case when m1.type = 'request' then 1 else 0 end) as requests,
SUM(case when m1.type = 'report' then 1 else 0 end) as reports
FROM companies c
LEFT JOIN messages m1 ON m1.companies_id = c.id
GROUP BY c.id;
I think, there is no required for two different joins;
SELECT
c.id,
sum(case when m1.type = 'request' then 1 else 0 end) as requests,
sum(case when m1.type = 'report' then 1 else 0 end) as reports
FROM companies c
LEFT JOIN messages m1 ON m1.companies_id = c.id
GROUP BY c.id;
The simplest solution would be to just count the distinct IDs:
SELECT c.*, COUNT(DISTINCT m1.id) as requests, COUNT(DISTINCT m2.id) as reports
FROM companies c
LEFT JOIN messages m1 ON m1.companies_id = c.id AND m1.type = 'request'
LEFT JOIN messages m2 ON m2.companies_id = c.id AND m2.type = 'report'
GROUP BY c.id;
You could simplify your query as to get different counts based on your types with single join clause
SELECT c.*,
SUM(m.type = 'request') as requests,
SUM(m.type = 'report') as reports
FROM companies c
LEFT JOIN messages m ON m.companies_id = c.id
GROUP BY c.id;
In Mysql if sum
is used conditional expression it will return as a boolean 0/1 based on if condition is met or not
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.