MYSQL group by and counting columns - mysql

Say I have a table like this:
+--------+-------+
| ID | LETTER|
+--------+-------+
| 1 | A |
| 1 | A |
| 1 | A |
| 2 | A |
| 2 | B |
| 3 | C |
| 3 | D |
| 4 | D |
+--------+-------+
How would I implement a query that returns the ID followed by how many unique letters it has? So it would look like this:
+--------+-------+
| ID | LETTER|
+--------+-------+
| 1 | 1 |
| 2 | 2 |
| 3 | 2 |
| 4 | 1 |
+--------+-------+
I've tried using group by but I cant figure it out.

You should search for the answer before questioning. But here is what you need:
SELECT yt.ID, COUNT(DISTINCT yt.LETTER)
FROM yourtable yt
GROUP BY yt.ID

Related

Query equivalent to two group by's without a subquery?

I'm trying to run a report on User ACL's. We use MYSQL and my we're prohibited from using subqueries for performance reasons. The goal is to turn this:
--------------------------------
| userName | folderID | roleID |
--------------------------------
| gronk | 1 | 1 |
| gronk | 2 | 2 |
| gronk | 4 | 2 |
| tbrady | 1 | 2 |
| jedelman | 1 | 1 |
| jedelman | 2 | 1 |
| mbutler | 1 | 2 |
| mbutler | 2 | 2 |
| bill | 1 | 3 |
| bill | 2 | 3 |
| bill | 3 | 3 |
| bill | 4 | 3 |
--------------------------------
Into this:
------------------------
| Lowest Role | Number |
------------------------
| 1 | 2 |
| 2 | 2 |
| 3 | 1 |
------------------------
I can see how to do it with a subquery. The inner query would do a group by on userName with a min(roleID). Then the outer query would do a group by on the lowest role and count(*). But I can't see how to do it without a subquery.
Also, if it helps I created a SQL Fiddle that has the data above.
I found a solution using a left join:
select UFM.roleID, count(distinct UFM.userName)
from UserFolderMembership UFM
left join UserFolderMembership UFM2 on
UFM.userName = UFM2.userName and
UFM.roleID > UFM2.roleID
where
UFM2.userName is null
group by
UFM.roleID

MySQL group by names separated by commas

I received a CSV file and one of the columns has names like Jack,Clark,James in one cell. Another will just have James, then another with be Clark,James. Is there a way I can GROUP BY and COUNT(*) without giving them all their own rows?
Ignoring for a moment the old adage that says "just because you can do something, it doesn't mean that you should", and noting the presence of a PRIMARY KEY in my data set, which is absent from yours...
SELECT * FROM ints;
+---+
| i |
+---+
| 0 |
| 1 |
| 2 |
| 3 |
| 4 |
| 5 |
| 6 |
| 7 |
| 8 |
| 9 |
+---+
SELECT * FROM my_table;
+----+--------------------+
| id | names |
+----+--------------------+
| 1 | steve,james,carlos |
| 2 | james |
| 3 | carlos,steve |
| 4 | james,jack |
+----+--------------------+
SELECT name
, COUNT(*) total
FROM
( SELECT DISTINCT id
, SUBSTRING_INDEX(SUBSTRING_INDEX(names,',',i),',',-1) name
FROM my_table x
, ints
) a
GROUP
BY name;
+--------+-------+
| name | total |
+--------+-------+
| | 4 |
| carlos | 2 |
| jack | 1 |
| james | 3 |
| steve | 2 |
+--------+-------+

MYSQL: How to get a group total repeating in column while keeping the grouping

Generated results that look like this:
------------------------
|GROUP A|GROUP B|AMOUNT|
------------------------
| A | 1 | 5 |
| A | 2 | 4 |
| B | 1 | 4 |
| B | 2 | 2 |
| B | 3 | 6 |
| C | 1 | 1 |
| C | 2 | 4 |
------------------------
Looking to sum in a new column the total of GROUP A that repeats along GROUP B:
---------------------------------------
|GROUP A|GROUP B|AMOUNT|SUM of GROUP A|
---------------------------------------
| A | 1 | 5 | 9 |
| A | 2 | 4 | 9 |
| B | 1 | 4 | 12 |
| B | 2 | 2 | 12 |
| B | 3 | 6 | 12 |
| C | 1 | 1 | 5 |
| C | 2 | 4 | 5 |
---------------------------------------
I'm using several derived and joined tables, so hoping this would be easy enough to calculate within the current SELECT statement or another derived table. Any ideas? Can't add additional rows using WITH ROLLUP modifier.
Try something like this:
SELECT t1.*, SumOfGroup_A
FROM mytable AS t1
INNER JOIN (
SELECT GROUP_A, SUM(AMOUNT) AS SumOfGroup_A
FROM mytable
GROUP BY GROUP_A
) t2 ON t1.GROUP_A = t2.GROUP_A
Demo here

MySQL complex ORDER BY issue

I have a complicated ordering issue in my query.
Raw, Unordered Data:
+------+--------+-----------+
| id | job_id | action_id |
+------+--------+-----------+
| 1 | 2 | 1 |
| 2 | 2 | 2 |
| 3 | 1 | 1 |
| 4 | 2 | 3 |
| 5 | 4 | 1 |
| 6 | 1 | 2 |
| 7 | 3 | 1 |
| 8 | 3 | 2 |
| 9 | 4 | 2 |
+------+--------+-----------+
Required Ordering:
+------+--------+-----------+
| id | job_id | action_id |
+------+--------+-----------+
| 7 | 3 | 1 |
| 8 | 3 | 2 |
| | | | * blank lines added for clarity,
| 5 | 4 | 1 | not desired in actual data
| 9 | 4 | 2 |
| | | |
| 3 | 1 | 1 |
| 6 | 1 | 2 |
| | | |
| 1 | 2 | 1 |
| 2 | 2 | 2 |
| 4 | 2 | 3 |
+------+--------+-----------+
The theory behind this ordering:
the largest id is the most recently added entry
the most recent id with action_id of 1
followed by the entries with ascending action_ids that have the same job_id
then the next most recent action_id of 1
ad infinitum
EDIT: I'm not able to add columns to the table in order to aid in sorting, as I've seen in some other solutions to ordering questions.
Any help is greatly appreciated!
My best shot is this:
SELECT * FROM tbl
ORDER BY FIND_IN_SET(job_id,
(SELECT GROUP_CONCAT(job_id ORDER BY ID DESC)
FROM tbl WHERE action_id = 1));
I didn't find a way to do it easily, What do you think of the following code :
select c.id, c.job_id, c.action_id
from (select a.id, a.job_id, a.action_id, min(b.id) as related_id
from myTable a
inner join myTable b
on a.job_id=b.job_id
group by a.job_id) c
group by c.id
order by c.related_id desc, c.action_id

Is there a way in SQL (MySQL) to do a "round robin" ORDER BY on a particular field?

Is there a way in SQL (MySQL) to do a "round robin" ORDER BY on a particular field?
As an example, I would like to take a table such as this one:
+-------+------+
| group | name |
+-------+------+
| 1 | A |
| 1 | B |
| 1 | C |
| 2 | D |
| 2 | E |
| 2 | F |
| 3 | G |
| 3 | H |
| 3 | I |
+-------+------+
And run a query that produces results in this order:
+-------+------+
| group | name |
+-------+------+
| 1 | A |
| 2 | D |
| 3 | G |
| 1 | B |
| 2 | E |
| 3 | H |
| 1 | C |
| 2 | F |
| 3 | I |
+-------+------+
Note that the table may have many rows, so I can't do the ordering in the application. (I'd obviously have a LIMIT clause as well in the query).
I'd try something like:
SET #counter = 0;
SELECT (#counter:=#counter+1)%3 as rr, grp, name FROM table ORDER by rr, grp
What you can do is create a temporary column in which you create sets to give you something like this:
+-------+------+-----+
| group | name | tmp |
+-------+------+-----+
| 1 | A | 1 |
| 1 | B | 2 |
| 1 | C | 3 |
| 2 | D | 1 |
| 2 | E | 2 |
| 2 | F | 3 |
| 3 | G | 1 |
| 3 | H | 2 |
| 3 | I | 3 |
+-------+------+-----+
To learn how to create the sets, have a look at this question/answer.
Then its a simple
ORDER BY tmp, group, name
You can use MySQL variables to do this.
SELECT grp, name, #row:=#row+1 from table, (SELECT #row:=0) r ORDER BY (#row % 3);
+------+------+--------------+
| grp | name | #row:=#row+1 |
+------+------+--------------+
| 1 | A | 1 |
| 2 | D | 4 |
| 3 | G | 7 |
| 1 | B | 2 |
| 2 | E | 5 |
| 3 | H | 8 |
| 1 | C | 3 |
| 2 | F | 6 |
| 3 | I | 9 |
+------+------+--------------+