MySQL: Group By multiple fields and count - mysql

This type of question is answered in post "MySQL: Group By & Count Multiple Fields"
EDIT : Sample Query Used
SELECT actors.id AS actor_id, actors.act_name AS actor_name, details.registration_id AS
registration from games INNER JOIN actors ON actors.id = games.actor_id INNER JOIN
details ON details.id = games.detail_id WHERE 'some cond' GROUP BY registration, actor_id;
But, I'm unable to achieve it in my case. My table data is little different (I'm grouping the table by registration, actor_id). eg:
actor_id | actor_name | registration
----------------------------------------
189 | ABC | 1234-1234
189 | ABC | 4567-1234
189 | ABC | 7890-4321
169 | DEF | 1111-5643
169 | DEF | 1111-5643
and I expect the output as below
actor_id | actor_name | registration | actor_count
------------------------------------------------------
189 | ABC | 1234-1234 | 3
189 | ABC | 4567-1234 | 3
189 | ABC | 7890-4321 | 3
169 | DEF | 1111-5643 | 2
169 | DEF | 1111-5643 | 2
That is actor ABC has 3 occurrences in table and DEF has 2 occurrences, etc
Instead when I use count(*) I get an expected count of 1 in each row
But, Is there a way to achieve the above output?

You could achieve this by doing a sub query to the same table. Maybe something like this:
SELECT
actors.actor_id,
actors.actor_name,
actors.registration,
(
SELECT
COUNT(*)
FROM
actors AS innerActors
WHERE innerActors.actor_id=innerActors.actor_id
) AS actor_count
FROM
actors

You can achive your goal by joining your base table to an aggregation subquery (in mysql).
For example:
SELECT
A.actor_id, A.actor_name, A.registration, B.actor_count
FROM
YourTable AS A
INNER JOIN (
SELECT
actor_id, COUNT(1) AS actor_count
FROM
YourTable
GROUP BY
actor_id
) B
ON A.actor_id = B.actor_id

Write a subquery that gets the count for each actor. Then join this with the original table to put the count on each of their rows.
SELECT t1.actor_id, t1.actor_name, t1.registration, t2.actor_count
FROM YourTable AS t1
JOIN (SELECT actor_id, COUNT(*) AS actor_count
FROM YourTable
GROUP BY actor_id) AS t2 ON t1.actor_id = t2.actor_id
DEMO
If you include registration in the grouping, you'll get counts of 1 because the registration is different on each row.

Related

mysql count the number of matches based on a column

This is my example dataset I have groups with students assigned to them as shown below
uid | groupid | studentid
49 | PZV7cUZCnLwNkSS | wTsBSkkg4Weo8R3
50 | PZV7cUZCnLwNkSS | aIuDhxfChg3enCf
97 | CwvkffFcBCRbzdw | hEwLxJmnJmZFAic
99 | CwvkffFcBCRbzdw | OKFfl58XVQMrAyC
126 | CwvkffFcBCRbzdw | dlH8udyTjNV3nXM
142 | 2vu1eqTCWVjgE58 | Q01Iz3lC2uUMBSB
143 | 2vu1eqTCWVjgE58 | vB5s8hfTaVtx3wO
144 | 2vu1eqTCWVjgE58 | 5O9HA5Z7wVhgi6l
145 | 2vu1eqTCWVjgE58 | OiEUOXNjK2D2s8F
I am trying to output with the following information.
The problem I am having is the Group Size column getting it to output a count.
Studentid | Groupid | Group Size
wTsBSkkg4Weo8R3 | PZV7cUZCnLwNkSS | 2
aIuDhxfChg3enCf | PZV7cUZCnLwNkSS | 2
hEwLxJmnJmZFAic | CwvkffFcBCRbzdw | 3
OKFfl58XVQMrAyC | CwvkffFcBCRbzdw | 3
dlH8udyTjNV3nXM | CwvkffFcBCRbzdw | 3
I have researched if I can you can use a where clause in the count, and does not seem like it will let me do that. I thought about doing a sum but couldn't make that happen either. I feel like I am missing something simple.
An easy way to solve this, is using a JOIN statement:
SELECT a.studentid AS Studentid, a.groupid AS Groupid, COUNT(*)
FROM table AS a
JOIN table AS b ON a.groupid = b.groupid
GROUP BY a.studentid, a.groupid
So here we join the table with itself and use a GROUP BY to group on the studentid and groupid and then use COUNT(*) to count the number of rows in b that have the same groupid.
Try this:
SELECT *
FROM pony a
LEFT JOIN (
SELECT COUNT(*), groupid
FROM pony
GROUP BY groupid
) b ON a.groupid = b.groupid
try this
SELECT T1.Studentid, T1.Groupid, T2.GroupCount
FROM Your_Table T1
INNER JOIN ( SELECT Groupid, count(*) AS GroupCount FROM Your_Table GROUP BY Groupid ) T2
ON T1.Groupid = T2.Groupid
You should try:
SELECT COUNT(Groupid) AS Groupsize FROM table;
It seems that what you're trying to do is simple. If I understand correctly, a simple SELECT COUNT statement. To exclude multiple returns of the same value, use SELECT DISTINCT COUNT()

Get total count of records with a mysql join and 2 tables

I have 2 tables that I am trying to join but I am not sure how to make it the most time efficient.
Tasks Table:
nid | created_by | claimed_by | urgent
1 | 11 | 22 | 1
2 | 22 | 33 | 1
3 | 33 | 11 | 1
1 | 11 | 43 | 0
1 | 11 | 44 | 1
Employee Table:
userid | name
11 | EmployeeA
22 | EmployeeB
33 | EmployeeC
Result I am trying to get:
userid | created_count | claimed_count | urgent_count
11 | 3 | 1 | 3
22 | 1 | 1 | 2
33 | 1 | 1 | 2
created_account column will show total # of tasks created by that user.
claimed_count column will show total # of tasks claimed by that user.
urgent_count column will show total # of urgent tasks (created or claimed) by that user.
Thanks in advance!
I would start by breaking this up into pieces and then putting them back together. You can get the created_count and claimed_count using simple aggregation like this:
SELECT created_by, COUNT(*) AS created_count
FROM myTable
GROUP BY created_by;
SELECT claimed_by, COUNT(*) AS claimed_count
FROM myTable
GROUP BY claimed_by;
To get the urgent count for each employee, I would join the two tables on the condition that the employee is either the created_by or claimed_by column, and group by employee. Instead of counting, however, I would use SUM(). I am doing this because it appears each row will be either 0 or 1, so SUM() will effectively count all non-zero rows:
SELECT e.userid, SUM(t.urgent)
FROM employee e
JOIN task t ON e.userid IN (t.created_by, t.claimed_by)
GROUP BY e.userid;
Now that you have all the bits of data you need, you can use an outer join to join all of those subqueries to the employees table to get their counts. You can use the COALESCE() function to replace any null counts with 0:
SELECT e.userid, COALESCE(u.urgent_count, 0) AS urgent_count, COALESCE(crt.created_count, 0) AS created_count, COALESCE(clm.claimed_count, 0) AS claimed_count
FROM employee e
LEFT JOIN(
SELECT e.userid, SUM(t.urgent) AS urgent_count
FROM employee e
JOIN task t ON e.userid IN (t.created_by, t.claimed_by)
GROUP BY e.userid) u ON u.userid = e.userid
LEFT JOIN(
SELECT claimed_by, COUNT(*) AS claimed_count
FROM task
GROUP BY claimed_by) clm ON clm.claimed_by = e.userid
LEFT JOIN(
SELECT created_by, COUNT(*) AS created_count
FROM task
GROUP BY created_by) crt ON crt.created_by = e.userid;
Here is an SQL Fiddle example.

How to write this MYSQL Query with count

So i have the following table:
userid | name | referralcode
When users register on the website they put the referralcode of someone else (the referral code is the same number as the userid of someone else)
so im looking for a sql query that will output something like this
20 (this means 20 users have this userid on their referral code) , Gerardo Bastidas, Valencia
10 , Juan Bastidas, Valencia
I want to get all info on user. its all located in the same table.
Try this query:
SELECT yt1.*, COALESCE(yt2.referral_count, 0)
FROM yourtable yt1 LEFT JOIN
(
SELECT t1.userid, COUNT(*) AS referral_count
FROM yourtable t1 INNER JOIN yourtable t2
ON t1.userid = t2.referralcode
GROUP BY t1.userid
) yt2
ON yt1.userid = yt2.userid;
This query does a self-join and will list every user along with the number of referral codes where his userid appears.
This code will do the work in one query. Replace your table name with 'tbName'
Tested and working
SELECT countval, userid, email, address
FROM tbName t1 LEFT JOIN
(
SELECT COUNT(t2.userid) ASs countval, tt.userid AS xx
FROM tbName t2
GROUP BY t2.referralcode
) t3
ON t3.xx = t1.userid
Output:
+-------+-----+------+
| count | uid | name |
+-------+-----+------+
| 3 | 1 | abc |
| 2 | 2 | xyz |
| 5 | 3 | kmn |
+-------+-----+------+

Select each row of table except where the id is not the maximum value for a given foreign key

Given a table such as the following called form_letters:
+---------------+----+
| respondent_id | id |
+---------------+----+
| 3 | 1 |
| 7 | 2 |
| 7 | 3 |
+---------------+----+
How can I select each of these rows except the ones that do not have the maximum id value for a given respondent_id.
Example results:
+---------------+----+
| respondent_id | id |
+---------------+----+
| 3 | 1 |
| 7 | 3 |
+---------------+----+
Something like this should work;
SELECT respondent_id, MAX(id) as id FROM form_letters
group by respondent_id
MySQL fiddle:
http://sqlfiddle.com/#!2/5c4dc0/2
There are many ways of doing it. group by using max(), or using not exits and using left join
Here is using left join which is better in terms of performance on indexed columns
select
f1.*
from form_letters f1
left join form_letters f2 on f1.respondent_id = f2.respondent_id
and f1.id < f2.id
where f2.respondent_id is null
Using not exits
select f1.*
from form_letters f1
where not exists
(
select 1 from form_letters f2
where f1.respondent_id = f2.respondent_id
and f1.id < f2.id
)
Demo
Here's how I would do it. Get the max id in a sub query, then join it back to your original table. Next, limit to records where the ID does not equal the max id.
Edit: Opposite of this. limit to records where the ID = MaxID. Code changed below.
Select FL.Respondent_ID, FL.ID, A.Max_ID
From Form_Letters FL
left join (
select Respondent_ID, Max(ID) as Max_ID
from Form_Letters
group by Respondent_ID) A
on FL.Respondent_ID = A.Respondent_ID
where FL.ID = A.Max_ID

mysql select top unique values with inner join

I have 2 tables that look like this:
users (uid, name)
-------------------
| 1 | User 1 |
| 2 | User 2 |
| 3 | User 3 |
| 4 | User 4 |
| 5 | User 5 |
-------------------
highscores (user_id, time)
-------------------
| 3 | 12005 |
| 3 | 29505 |
| 3 | 17505 |
| 5 | 19505 |
-------------------
I want to query only for users that have a highscore and only the top highscore of each user. The result should look like:
------------------------
| User 3 | 29505 |
| User 5 | 19505 |
------------------------
My query looks like this:
SELECT user.name, highscores.time
FROM user
INNER JOIN highscores ON user.uid = highscores.user_id
ORDER BY time ASC
LIMIT 0 , 10
Actually this returns multiple highscores of the same user. I also tried to group them but it did not work since it did not return the best result but a random one (eg: for user id 3 it returned 17505 instead of 29505).
Many thanks!
You should use the aggregated function MAX() together with group by clause.
SELECT a.name, MAX(b.`time`) maxTime
FROM users a
INNER JOIN highscores b
on a.uid = b.user_id
GROUP BY a.name
SQLFiddle Demo
Your effort of grouping users was correct. You just needed to use MAX(time) aggregate function instead of selecting only time.
I think you wrote older query was like this:
SELECT name, time
FROM users
INNER JOIN highscores ON users.uid = highscores.user_id
GROUP BY name,time
But actual query should be:
SELECT user.name, MAX(`time`) AS topScore
FROM users
INNER JOIN highscores ON users.uid = highscores.user_id
GROUP BY user.name