I have read the different answers here on SO, but I am stuck on this question. Please help.
I have this mysql view named "activeuser":
userid COUNT(*) ACRONYM
1 23 admin
2 2 doe
3 4 tompa
12 4 Marre
13 1 Mia
1 2 admin
3 1 tompa
12 1 Marre
13 1 Mia
2 1 doe
3 1 tompa
12 1 Marre
How can I sum the COUNT column so that I get the following wanted result?
userid COUNT(*) ACRONYM
1 25 admin
2 3 doe
3 6 tompa
12 6 Marre
13 1 Mia
EDITED:
I used this query to create the view:
CREATE VIEW activeuser AS
(SELECT boats_comments.userid, COUNT(boats_comments.userid), boats_user.acronym, boats_user.email
FROM boats_comments
INNER JOIN boats_user
ON boats_comments.userid = boats_user.id
GROUP BY boats_comments.userid
ORDER BY COUNT(boats_comments.userid) DESC)
UNION ALL
(SELECT boats_answers.userid, COUNT(boats_answers.userid), boats_user.acronym, boats_user.email
FROM boats_answers
INNER JOIN boats_user
ON boats_answers.userid = boats_user.id
GROUP BY boats_answers.userid
ORDER BY COUNT(boats_answers.userid) DESC)
UNION ALL
(SELECT boats_questions.userid, COUNT(boats_questions.userid), boats_user.acronym, boats_user.email
FROM boats_questions
INNER JOIN boats_user
ON boats_questions.userid = boats_user.id
GROUP BY boats_questions.userid
ORDER BY COUNT(boats_questions.userid) DESC)
My goal is to see which users are the most active by checking the number of comments, questions and answers... but I got stuck...
As the results in your view has duplicates I guess the underlying code for the view is grouping on something it maybe shouldn't be grouping on.
You can get the results you want by applying SUM to it:
select userid, sum("whatever column2 is named") as "Count", Acronym
from activeuser group by userid, Acronym;
select userid, count(*) from activeuser group by userid;
Related
How do you choose the employee who has worked the most night shifts of all time? There are 2 tables, one with workers, the second with night shifts, in which 2 people work per shift.
Users:
id
name
1
Oliver
2
Harry
3
Jacob
Hours:
id
NightShift1
NightShift2
1
1
3
2
2
2
3
3
1
4
3
2
5
2
2
6
1
2
7
1
3
8
3
1
To do this you can to essentially loop over the hours table twice; you do this by joining an ad hoc table specifying which shift you are looking at:
select users.id, users.name
from hours
join (select 1 position union all select 2) position
join users on users.id=if(position=1,hours.NightShift1,hours.NightShift2)
group by users.id
order by count(*) desc
limit 1
You can UNION the Hours table on top of itself and then group by the user id to see who has the highest count:
SELECT COUNT(*) as nightshiftcount, userid
FROM (
SELECT NightShift1 as userid FROM Hours
UNION ALL SELECT NightShift2 FROM Hours
) as hrs
ORDER BY nightshiftcount DESC
LIMIT 1
If you need the name, you can just INNER JOIN to that table in that outer FROM clause and pull that column through.
I am currently working on a project while trying to learn MySQL and I would like to join three tables and get the latest status for each related shipment. Here are the tables I'm working with (with example data):
shipments
id
consignee
tracking_number
shipper
weight
import_no
1
JOHN BROWN
TBA99900000121
AMAZON
1
101
2
HELEN SMITH
TBA99900000190
AMAZON
1
102
3
JACK BLACK
TBA99900000123
AMAZON
1
103
4
JOE BROWM
TBA99900000812
AMAZON
1
104
5
JULIA KERR
TBA99900000904
AMAZON
1
105
statuses
id
name
slug
1
At Warehouse
at_warehouse
2
Ready For Pickup
ready_for_pickup
3
Delivered
delivered
shipment_status (pivot table)
id
shipment_id
status_id
1
1
1
2
2
1
3
3
1
4
4
1
5
5
1
6
1
2
7
2
2
8
3
2
9
4
2
10
5
2
all tables do have created_at and updated_at timestamp columns
Example of the results I'm trying to achieve
slug
shipment_id
status_id
ready_for_pickup
1
2
ready_for_pickup
2
2
ready_for_pickup
3
2
ready_for_pickup
4
2
ready_for_pickup
5
2
Here's the query I wrote to try to achieve what I'm looking for based on examples and research I did during the past couple of days. I find that sometimes there is sometimes a mismatch with the latest status that relates to the shipment
SELECT
statuses.slug AS slug,
MAX(shipments.id) AS shipment_id,
statuses.id AS status_id,
FROM
`shipments`
INNER JOIN `shipment_status` ON `shipment_status`.`shipment_id` = `shipments`.`id`
INNER JOIN `statuses` ON `shipment_status`.`status_id` = `statuses`.`id`
GROUP BY
`shipment_id`
Because we need to reference other fields from the same record that evaluates from the MAX aggregation, you need to do it in two steps, there are other ways, but I find this syntax simpler:
SELECT
shipments.id AS id,
statuses.slug AS slug,
statuses.id AS status_id,
shipment_status.shipment_id as shipment_id
FROM
`shipments`
INNER JOIN `shipment_status` ON `shipment_status`.`shipment_id` = `shipments`.`id`
INNER JOIN `statuses` ON `shipment_status`.`status_id` = `statuses`.`id`
WHERE
shipment_status.id = (
SELECT MAX(shipment_status.id)
FROM `shipment_status`
WHERE shipment_status.shipment_id = shipments.id
)
try it out!
This query makes the assumption that the id field is an identity column, so the MAX(shipment_status.id) represents only the most recent status for the given shipment_id
You can use window functions:
SELECT s.id, st.slug, st.id
FROM shipments s JOIN
(SELECT ss.*,
ROW_NUMBER() OVER (PARTITION BY shipment_id ORDER BY ss.id DESC) as seqnum
FROM shipment_status ss
) ss
ON ss.shipment_id = s.id JOIN
statuses st
ON ss.status_id` = st.id
WHERE ss.seqnum = 1;
Also note the use of table aliases so the query is easier to write and to read.
I know that you can use the GROUP BY keyword to group by multiple columns, but here's what I'm trying to do:
Table: Codes
user_id day_of_week id
------------------------------
1 T 1
1 W 2
1 W 3
2 F 4
2 F 5
2 M 6
And I am trying to find a command to output to get this:
Table: Codes
user_id day_of_week count(*)
-------------------------------------
1 T 1
1 W 2
2 F 2
2 M 1
So as you can see, it's grouping by the day of the week and the user_id Can someone help me achieve this with MySQL?
You can use multiple columns in GROUP BY clause:
SELECT user_id, day_of_week, COUNT(*) AS cnt
FROM Codes
GROUP BY user_id, day_of_week
The title makes it sound easy but what I'd like to do is get the last 20 groups from the groups table, ordered by their corresponding users last login date. A group can have one or more users and ultimately what I want to do is find out which groups have had the least user activity and retrieve the last login date.
Here's the query I came up with -
SELECT DISTINCT g.name, user_max.max_login_last_at FROM groups g
LEFT JOIN group_user gu on g.id = gu.group_id
LEFT JOIN (
SELECT MAX(login_last_at) max_login_last_at, u.id
FROM users u GROUP BY id
) AS user_max ON (user_max.id = gu.user_id)
ORDER BY user_max.max_login_last_at ASC
The problem is when I perform the join, it pulls in every group_user record and results in duplicates. I feel like there could be an easy solution to this one but I can't seem to figure it out!
groups table
id name
1 Group 1
2 Group 2
users table
id email login_last_at
1 user1#example.com 2018-10-17 16:08:47
2 user2#example.com 2018-10-02 15:41:53
3 user3#example.com NULL
4 user4#example.com 2018-10-08 12:01:48
5 user5#example.com 2018-10-15 9:24:57
6 user6#example.com 2018-10-17 11:10:58
7 user7#example.com 2018-10-17 15:33:03
group_user table
id group_id user_id
1 1 1
2 2 1
3 1 2
4 1 3
5 1 4
6 2 5
7 1 5
8 2 6
9 1 7
Current example result -
name max_login_last_ts
Group 1 2018-10-02 15:41:53
Group 1 2018-10-08 12:01:48
Group 2 2018-10-15 09:24:57
Group 1 2018-10-15 09:24:57
Group 2 2018-10-17 11:10:58
Group 1 2018-10-17 15:33:03
Group 1 2018-10-17 16:08:47
Group 2 2018-10-17 16:08:47
Group 1 2018-10-18 08:55:17
The problem is as you can see in the result above is that I'm getting all groups, all I really want is the following -
name max_login_last_ts
Group 2 2018-10-17 16:08:47
Group 1 2018-10-18 08:55:17
Thanks in advance!
I think this query will do what you want. There isn't enough data in your sample to replicate your desired results though.
SELECT g.name, MAX(u.login_last_at) AS max_login_last_at
FROM `groups` g
JOIN group_user gu on gu.group_id = g.id
JOIN users u ON u.id = gu.user_id
GROUP BY g.name
ORDER By max_login_last_at DESC
LIMIT 20
Demo on dbfiddle
I have 3 tables which I need to query where I need to group by 2 columns and also join the tables but still return all results.
Users
ID User_name Category Reason Change_date
1 John 1 2 2016-01-05
2 James 3 1 2015-10-02
3 Peter 1 4 2016-01-04
4 Tony 1 4 2016-01-15
5 Fred 1 4 2016-02-25
6 Rick 3 2 2016-04-19
7 Sonia 2 1 2016-10-14
8 Michelle 2 2 2015-11-09
9 Phillip 3 3 2016-03-01
10 Simon 3 3 2016-03-07
Category
ID Category_name
1 User
2 Super user
3 Admin
Reason
ID Reason_name
1 Promotion
2 Upgrade
3 Sponsor
4 Normal
I did some searching and found https://stackoverflow.com/a/28158276/1278201 and modified my query to try and use it:
SELECT category_name, reasons.reason_name, u1.id as user_id, user_name
from users as u1
JOIN (SELECT id from users where users.change_date BETWEEN '2016-01-01'
AND '2016-11-06' group by users.category, users.reason) AS u2
ON u1.id = u2.id
left join reason on u1.reason=category.id
left join category on u1.category=category.id
The results being returned are only using the group by - I should have 8 rows returned but I am only getting 5 which is one for each occurrence of each reason within each category.
My expected outcome is:
category_name reason_name user_id user_name
User Upgrade 1 John
"Upgrade" count 1
Normal 3 Peter
4 Tony
5 Fred
"Normal" count 3
"User" count 4
Super user Promotion 7 Sonia
"Promotion" count 1
"Super user" count 1
Admin Upgrade 6 Rick
"Upgrade" count 1
Sponsor 9 Phillip
10 Simon
"Sponsor" count 2
"Admin" count 3
How can I get all 8 rows returned as well as being able to get counts for each category_name and reason_name?
For what you are looking for in the expected output, this might be what you looking for:
SELECT
Category_name, reason_name, users.ID,User_name
FROM
Users
inner join Category on Category.ID=Users.Category
inner join Reason on Reason.ID=Users.Reason
where users.change_date BETWEEN '2016-01-01' AND '2016-11-06'
SQLFiddle
You shouldn't use GROUP BY in the subquery, because then it only returns one user ID from each group.
In fact, you don't need the subquery at all. You can just use a WHERE clause to select users that meet the change_date criteria.
SELECT category_name, reasons.reason_name, u1.id as user_id, user_name
from users as u1
left join reason on u1.reason=category.id
left join category on u1.category=category.id
where u1.change_date BETWEEN '2016-01-01' AND '2016-11-06'
To get subtotals of the groupings by category and reason, you can use GROUP BY and WITH ROLLUP.
SELECT category_name, reasons.reason_name, u1.id as user_id, user_name, COUNT(*) AS total
from users as u1
left join reason on u1.reason=category.id
left join category on u1.category=category.id
where u1.change_date BETWEEN '2016-01-01' AND '2016-11-06'
GROUP BY category_name, reason_name, user_id WITH ROLLUP
In the script that displays the results, the totals are in the rows where user_id is NULL. The category totals also have reason IS NULL. So you can display these rows appropriately in the script that displays the results. If you really need to do it all in MySQL, you can put the above query in a subquery, and the containing query can test for user_id IS NULL and reason_name IS NULL.