Reputation: 1063
I'm working on a simple query over two tables and I'm trying to count the number of records with the same ID I would have got if I didn't group them. These are the tables:
id -- type -- user_id -- field_id
1 -- painting -- 53 -- 12
2 -- reading -- 53 -- 12
3 -- writing -- 53 -- 12
id -- is_test -- user_id -- field_id
7 -- Yes -- 53 -- 12
8 -- No -- 53 -- 12
With this query I get the single record that I want from the table jobs
(painting) because I'm using the GROUP BY
clause on the column jobs.id
. If I didn't use the GROUP BY, I would get 2 records because there are 2 matching activities for the same user_id
and field_id
.
SELECT `jobs`.*,`activities`.`is_test`
FROM `jobs`
LEFT JOIN `activities` ON `activities`.`user_id`=`jobs`.`user_id`
WHERE `jobs`.`field_id`=12 AND `activities`.`field_id`=12 AND `jobs`.`type`='painting' AND `jobs`.`user_id`=53
GROUP BY `jobs`.`id`
ORDER BY `jobs`.`id` DESC;
What I'm trying to do is to fetch another column containing the actual number of matching records in the table activities
. Basically I want to get 2 as count of records in activities
with the same user_id
and field_id
.
I have tried to select the new column like this:
SELECT `jobs`.*,`activities`.`is_test`, COUNT(DISTINCT `jobs`.`id`) AS `tot_act`
but this obviously returns 1 rather than 2 for the new column tot_act
. Making it count the field activities.is_test
did not work either.
I was trying to avoid a sub-select.
Please do not pay attention to the column activities.is_test
, I don't care to see if it's set to Yes or No, I just want to count that there is a matching record for Yes and one for No so 2 records in total if I don't group them. 2 is the value I'm trying to retrieve as a new column.
Any ideas will be much appreciated!
Upvotes: 0
Views: 1070
Reputation: 35603
COUNT() increments by 1 for each NON NULL value it encounters.
In your case you want the count of rows from the activities table, not the jobs table.
SELECT
jobs.id
, jobs.type
, jobs.user_id
, Jobs.field_id
, COUNT(activities.id) activity_count
FROM jobs
LEFT JOIN activities ON jobs.user_id = activities.user_id
AND activities.field_id = 12
WHERE jobs.field_id = 12
AND jobs.type = 'painting'
AND jobs.user_id = 53
GROUP BY
jobs.id
, jobs.type
, jobs.user_id
, Jobs.field_id
ORDER BY
jobs.id DESC;
from your sample data that query produces this result:
| id | type | user_id | field_id | activity_count |
|----|----------|---------|----------|----------------|
| 1 | painting | 53 | 12 | 2 |
Note however that if you include activity.is_test in the select and grouping clauses then you will not get a count of 2.
see this sqlfiddle
Upvotes: 1
Reputation: 48387
Your first query doesn't make any sense. Group by only has meaning combined with an aggregate function in the output columns (select clause).
The where filter on activities.field_id is (expensively) converting the left join into an inner join.
I also suspect your schema is not normalised.
to fetch another column containing the actual number of matching records in the table activities
SELECT `jobs`.id, jobs.type, jobs.user_id,
Jobs.field_id,`activities`.`is_test`,
SUM(IF(activities.id IS NULL, 0,1))
FROM `jobs`
LEFT JOIN `activities`
ON `activities`.`user_id`=`jobs`.`user_id`
AND activities.field_id=12
WHERE `jobs`.`field_id`=12
AND `jobs`.`type`='painting'
AND `jobs`.`user_id`=53
GROUP BY `jobs`.id, jobs.type, jobs.user_id,
Jobs.field_id,`activities`.`is_test`
ORDER BY `jobs`.`id` DESC;
Upvotes: 1
Reputation: 5522
SELECT
`jobs`.id,
`jobs`.type,
`jobs`.user_id,
`jobs`.field_id,
count(1) as activities_count,
max(`activities`.is_test) as is_test
FROM
`jobs`
LEFT OUTER JOIN
`activities` ON
`activities`.user_id = `jobs`.user_id
AND `activities`.field_id = `jobs`.field_id
WHERE
`jobs`.field_id = 12
AND `jobs`.type = 'painting'
AND `jobs`.user_id = 53
GROUP BY
`jobs`.id,
`jobs`.type,
`jobs`.user_id,
`jobs`.field_id
Upvotes: 0