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()
Related
I have two tables in MySQL:
___Table1
| id | name |
|----|------|
| 98 | Fred |
___Table2
| link | amount |
|------|--------|
| 98 | 100.00 |
| 98 | 50.00 |
How can I SELECT all the items from ___Table1 and SUM datas from the ___Table2.
The desired output should be:
Fred = 150.00
This is what I have tried so far:
SELECT
SELECT SUM(amount) AS amount FROM ___Table2 WHERE ___Table2.link = ___Table1.id,
(SELECT * FROM ___Estimates ORDER BY EST_Id DESC)
Thanks.
SELECT
t1.id AS id,
t1.name as name,
IFNULL ( SUM( t2.amount ), 0 ) AS account
FROM
___Table2 t2
RIGHT JOIN ___Table1 t1 ON t2.link = t1.id
GROUP BY
t2.link
You could group by name instead but you didn't say if it was unique. If you just need a single user then add a where clause to select that user:
select name, sum(amount) as 'sum'
from ___Table1
join ___Table2 on ___Table1.id = ___Table2.link
group by ___Table1.id
Those table names are awful (you can't tell how many underscores by just looking at it), also it's a good idea to use the same name for the primary and foreign key (_id is the often used standard).
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
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.
I have a table as so...
----------------------------------------
| id | name | group | number |
----------------------------------------
| 1 | joey | 1 | 2 |
| 2 | keidy | 1 | 3 |
| 3 | james | 2 | 2 |
| 4 | steven | 2 | 5 |
| 5 | jason | 3 | 2 |
| 6 | shane | 3 | 3 |
----------------------------------------
I'm running a select like so:
SELECT * FROM table WHERE number IN (2,3);
The problem im trying to solve is that I want to only grab get results from groups that have 1 or more rows of each number. For instance the above query is returning id's 1-2-3-5-6, when I'd like the results to exclude id 3 since the group of '2' can only return 1 result for the number of '2' and not for BOTH 2 and 3, since there's no row with the number 3 for the group 2 i'd like it to not even select id 3 at all.
Any help would be great.
Try it this way
SELECT *
FROM table1 t
WHERE number IN(2, 3)
AND EXISTS
(
SELECT *
FROM table1
WHERE number IN(2, 3)
AND `group` = t.`group`
GROUP BY `group`
HAVING MAX(number = 2) > 0
AND MAX(number = 3) > 0
)
or
SELECT *
FROM table1 t JOIN
(
SELECT `group`
FROM table1
WHERE number IN(2, 3)
GROUP BY `group`
HAVING MAX(number = 2) > 0
AND MAX(number = 3) > 0
) q
ON t.`group` = q.`group`;
or
SELECT *
FROM table1
WHERE `group` IN
(
SELECT `group`
FROM table1
WHERE number IN(2, 3)
GROUP BY `group`
HAVING MAX(number = 2) > 0
AND MAX(number = 3) > 0
);
Sample output (for both queries):
| ID | NAME | GROUP | NUMBER |
|----|-------|-------|--------|
| 1 | joey | 1 | 2 |
| 2 | keidy | 1 | 3 |
| 5 | jason | 3 | 2 |
| 6 | shane | 3 | 3 |
Here is SQLFiddle demo
On this, you can approach from a fun way with multiple joins for what you WANT qualified, OR, apply a prequery to get all qualified groups as others have suggested, but readability is a bit off for me..
Anyhow, here's an approach going through the table once, but with joins
select DISTINCT
T.id,
T.Name,
T.Group,
T.Number
from
YourTable T
Join YourTable T2
on T.Group = T2.Group AND T2.Group = 2
Join YourTable T3
on T.Group = T3.Group AND T3.Group = 3
where
T.Number IN ( 2, 3 )
So on the first record, it is pointing to by it's own group to the T2 group AND the T2 group is specifically a 2... Then again, but testing the group for the T3 instance and T3's group is a 3.
If it cant complete the join to either of the T2 or T3 instances, the record is done for consideration, and since indexes work great for joins like this, make sure you have one index for your NUMBER criteria, and another index on the (GROUP, NUMBER) for those comparisons and the next query sample...
If doing by more than this simple 2, but larger group, prequery qualified groups, then join to that
select
YT2.*
from
( select YT1.group
from YourTable YT1
where YT1.Number in (2, 3)
group by YT1.group
having count( DISTINCT YT1.group ) = 2 ) PreQualified
JOIN YourTable YT2
on PreQualified.group = YT2.group
AND YT2.Number in (2,3)
Maybe this,if I understand you
SELECT id FROM table WHERE `group` IN
(SELECT `group` FROM table WHERE number IN (2,3)
GROUP BY `group`
HAVING COUNT(DISTINCT number)=2)
SQL Fiddle
This will return all ids where BOTH numbers exist in a group.Remove DISTINCT if you want ids for groups where just one numbers is in.
I am trying to select the rows from a table by 'group by' and ignoring the first row got by sorting the data by date. The sorting should be done by a date field, to ignore the newest entry and returning the old ones for the group.
The table looks like
+----+------------+-------------+-----------+
| id | updated on | group_name | list_name |
+----+------------+----------------+--------+
| 1 | 2013-04-03 | g1 | l1 |
| 2 | 2013-03-21 | g2 | l1 |
| 3 | 2013-02-26 | g2 | l1 |
| 4 | 2013-02-21 | g1 | l1 |
| 5 | 2013-02-20 | g1 | l1 |
| 6 | 2013-01-09 | g2 | l2 |
| 7 | 2013-01-10 | g2 | l2 |
| 8 | 2012-12-11 | g1 | l1 |
+----+------------+-------------+-----------+
http://www.sqlfiddle.com/#!2/cec99/1
So, basically, I just want to return ids (3,4,5,6,8) as those are the oldest in the group_name and list_name. Ignoring the latest entry and returning the old ones by grouping it based on group_name and list_name
I am not able to write sql for this problem. I know order by will not work with group by. Please help me in figuring out a solution.
Thanks
And also, is there a way to do this without using subqueries?
Something like the following to get only the rows that are the minimum date for a specific row:
select a.ID, a.updated_on, a.group_name, list_name
from data a
where
a.updated_on <
(
select max(updated_on)
from data
group by group_name having group_name = a.group_name
);
SQL Fiddle: http://www.sqlfiddle.com/#!2/00d43/10
Update (based on your reqs)
select a.ID, a.updated_on, a.group_name, list_name
from data a
where
a.updated_on <
(
select max(updated_on)
from data
group by group_name, list_name having group_name = a.group_name
and list_name = a.list_name
);
See: http://www.sqlfiddle.com/#!2/cec99/3
Update (To not use Correlated Subquery but Simple subquery)
Decided correlated subquery is too slow based on: Subqueries vs joins
So I changed to joining with a aliased temporary table based on nested query.
select a.ID, a.updated_on, a.group_name, a.list_name
from data a,
(
select group_name, list_name , max(updated_on) as MAX_DATE
from data
group by group_name, list_name
) as MAXDATE
where
a.list_name = MAXDATE.list_name AND
a.group_name = MAXDATE.group_name AND
a.updated_on < MAXDATE.MAX_DATE
;
SQL Fiddle: http://www.sqlfiddle.com/#!2/5df64/8
You could try using the following query (yes, it has a nested join, but maybe it helps).
SELECT ID FROM
(select d1.ID FROM data d1 LEFT JOIN
data d2 ON (d1.group_name = d2.group_name AND d1.list_name=d2.list_name AND
d1.updated_on > d2.updated_on) WHERE d2.ID IS NULL) data_tmp;
CORRECTION:
SELECT DISTINCT(ID) FROM
(select d1.* FROM data d1 LEFT JOIN
data d2 ON (d1.group_name = d2.group_name AND d1.list_name=d2.list_name AND
d1.updated_on < d2.updated_on) WHERE d2.ID IS NOT NULL) date_tmp;
SELECT DISTINCT y.id
FROM data x
JOIN data y
ON y.group_name = x.group_name
AND y.list_name = x.list_name
AND y.updated_on < x.updated_on;