Alessio Firenze
Alessio Firenze

Reputation: 1063

MySQL COUNT records before GROUP BY

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:

TABLE jobs

id -- type -- user_id -- field_id

1 -- painting -- 53 -- 12

2 -- reading -- 53 -- 12

3 -- writing -- 53 -- 12

TABLE activities

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

Answers (3)

Paul Maxwell
Paul Maxwell

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

symcbean
symcbean

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

Lock
Lock

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

Related Questions