MySQL Query for Row with Most Recent Date - mysql

Let's say I have a table called "signup_info" as follows:
p_key_id name gender signup_date
1 Bob male 10/5/17
2 Mary female 9/23/14
3 Jamie female 2/6/15
4 Jamie male 3/22/17
How would I write a query that would only give me the most row pertaining to the most recent signup_date for every instance of a person's name?

I would use a correlated subquery:
select si.*
from signup_info si
where si.signup_date = (select max(s2.signup_date) from signup_info si2 where si2.name = si.name);
If p_key_id is autoincrementing, then it might provide a more reliable way to get the most recent:
select si.*
from signup_info si
where si.p_key_id = (select max(s2.p_key_id) from signup_info si2 where si2.name = si.name);
If someone signs up twice on the same date, then the first will return duplicate rows for that person.

Related

SQL group by function to categorize only the most recent data

So I have this table called title where it stores all of the title held by each employee which will look like this
emp_no
title
start_date
101
Engineer
2019-01-01
101
Senior Engineer
2020-02-01
102
Engineer
2019-01-11
102
Senior Engineer
2020-02-11
103
Engineer
2019-01-21
104
Engineer
2019-01-31
105
Associate
2019-01-01
106
Associate
2019-01-11
106
Manager
2020-02-11
107
Associate
2019-01-21
107
Manager
2020-02-21
108
Associate
2019-01-31
Notice that each employee can have more than 1 title. For example emp 101 title is engineer in 1st January 2019 but got promoted as senior engineer one year later.
Now lets say i want to count how many employees for each position. I have tried using the count function along with group by (to group the number of employee by the title) but the problem is, the SQL query also count the past position of every employee.
To be exact, I only want to include the most recent role that an employee currently has. So in this case, the result I am expecting is
Engineer: 2 employees (because the other 2 has been promotod to senior engineer),
Senior engineer: 2 employees,
Associate: 2 employees (because the other 2 has been promotod to manager),
Manager: 2 employees
Is there some kind of way to achieve that?
NOTE: this table format is from one of the SQL online course that i'm taking so I'm not the one who make the table. and also in the original table in containes tens of thousands of data.
You can use not exists as follows:
select title, count(*) as Count
from your_table t
where not exists
(select 1 from your_table tt
where tt.emp_no = t.emp_no and tt.start_date> t.start_date)
group by title
select title,COUNT(*) numberOfEmp from
(
select distinct emp_no
,(select top 1 title from [dbo].[Tbl_title] a where a.emp_no=m.emp_no
order by [start_date] desc
) title
from [dbo].[Tbl_title] m
) mTable
group by title
I am going to recommend a correlated subquery, but for a very particular reason:
select title, count(*)
from t
where t.start_date = (select max(t2.start_date)
from t t2
where t2.emp_no = t.emp_no
);
The particular reason for suggesting this is that it is easy to modify this for the number of employees "as of" a particular date. For instance, if you want the number of employees as of 2019-01-01, you change the where to:
where t2.emp_no = t.emp_no and t2.start_date <= '2019-01-01'
You can simply filter the data in where condition while counting. Query as follows:
select title, count(distinct emp_no) as Count
from (select emp_np, title, max(start_date) as start_date
from table
group by emp_np, title) subset
group by title

Selecting everything from table 1 with average AND distinct values from table 2 and table 3

I am not entirely sure even how to name this post, because I do not know exactly how to ask it.
I have three tables. One with users, one with foods and one with the users rating of the foods, like such (simplified example):
Foods
id name type
---------------------
1 Apple fruit
2 Banana fruit
3 Steak meat
Users
id username
-----------------
1 Mark
2 Harrison
3 Carrie
Scores (fid = food id, uid = user id)
fid uid score
---------------------
1 1 3
1 2 5
2 1 2
3 2 3
Now, I have this query, which works perfectly:
SELECT fn.name as Food, ROUND(AVG(s.score),1) AS AvgScore FROM Foods fn LEFT JOIN Scores s ON fn.id = s.fid GROUP BY fn.id ORDER BY fn.name ASC
As you can tell, it lists all names from Foods including an average from all users ratings of the food.
I also want to add the unique users own score. (Assume that when Mark is logged in, his uid is set in a session variable or whatever)
I need the following output, if you are logged in as Mark:
Food AvgScore Your Score
Apple 4 3
I have made several attempts to make this happen, but I cannot find the solution. I have learned that if you have a question, it is very likely that someone else has asked it before you do, but I do not quite know how to phrase the question, so I get no answers when googling. A pointer in the right direction would be much appreciated.
You can try with case:
SELECT fn.name as Food,
ROUND(AVG(s.score),1) AS AvgScore,
sum(case s.uid = $uid when s.score else 0 end) as YourScore
FROM Foods fn
LEFT JOIN Scores s ON fn.id = s.fid
GROUP BY fn.id
ORDER BY fn.name ASC
$uid is variable off course.

mySQL GROUP, most recent

Here is the data set:
Person Status Date
Eric 1 1/1/2015
Eric 2 2/1/2015
Eric 3 3/1/2015
John 1 3/1/2015
John 2 2/1/2015
John 1 1/1/2015
I'd like to get the most recent date, and its correlated status, grouped by Person. I tried using a subquery to first identify the most recent date:
SELECT MAX(Date), Person FROM tbl1 GROUP BY Person
And then joining that back into the original table, so that by person I know which date is the most recent. But I'm struggling how to identify the most recent status. I just don't see the appropriate aggregator. Thanks.
select tbl1.*
from tbl1
join
(
SELECT Person, MAX(Date) as m_date
FROM tbl1
GROUP BY Person
) tmp on tbl1.Person = tmp.Person
and tbl1.date = tmp.m_date

How can you decide which records of a JOINED table remains after a GROUP BY?

I'm trying to LEFT JOIN two tables and GROUP BY a field of the first table in MySQL.
If there are multiple rows in the second table for each record in the first one, a GROUP BY eliminates all records but one of the right table. Is there a way to determine which one it is?
To give you a specific example, I want to get a list of users, joined with the IDs of their (for example) most expensive purchases (or most recent purchases, or whatever..) It seems like an easy task, but I'm frustrated and have asolutely no idea how to do it!
Table 1: Users
userId, userName
1 Frank
2 Sarah
3 Tim
Table 2: Purchases
orderId, userId, value
1 3 14.99
2 2 9.99
3 3 79.99
4 1 2.99
5 2 14.99
SELECT * FROM Users LEFT JOIN Purchases ON Users.userId = Purchases.userId
will return:
userId, userName, orderId, value
1 Frank 4 2.99
2 Sarah 2 9.99
2 Sarah 5 14.99
3 Tim 1 14.99
3 Tim 3 79.99
Now if I GROUP BY userId the result will be:
userId, userName, orderId, value
1 Frank 4 2.99
2 Sarah 2 9.99
3 Tim 1 14.99
Is there a way to decide in this case which orderId is kept or is there a completely other and better way to do this?
I have tried some things like MAX() but this will always only return the highest value of the whole table, not individually for each user.
Thank you in advance, you awesome stackoverflow-community!
best Florian
In strict SQL this Query would not be valid as in a Group by context u should select only fields contained in the group by clause or aggregates.
Mysql however allows this syntax and handles it as "i dont care about this fields", you can not define which of the rows values is selected then.
But you can do it with a query like this:
SELECT u.*,p.* FROM Users u LEFT JOIN
( SELECT userId, max(value) as max_value FROM Purchases GROUP BY userId) p ON u.userId = p.userId
If you want to get the max() pusrchase per user preserving the order like orderid etc you may need to do this
select
u.userId,
u.userName,
p.orderId,
p.value
from Users u
inner join Purchases p on
p.userId = u.userId
inner join
(
select orderId,
max(value) as value,
userId
from Purchases
group by userId
)o
on o.userId = p.userId
AND o.value = p.value
group by u.userId
http://sqlfiddle.com/#!2/1afda/9

What is the statement to get counts for unique values in a table? [duplicate]

This question already has an answer here:
How to get the count of each distinct value in a column? [duplicate]
(1 answer)
Closed 9 years ago.
For example, if I had a table of DVDs people owned, like this
OWNER TITLE
---------------------------------
Jennifer | Ghostbusters
Jennifer | Jurassic Park
Alex | Titanic
Jennifer | Aliens
Jack | Seinfeld
Jack | Baby's Day Out
Alex | Jurassic Park
And I wanted to get a count of how many rows each OWNER had, like
Jennifer | 3
Alex | 2
Jack | 2
How would I do that? I know how to count how many OWNERs there are, but not how many rows each OWNER has. So far I've been using multiple statements -- select owner(distinct owner), make an array of the returned names, then issue a "select count from table where owner = array[i]" for each item in the array -- but that doesn't seem like the smart way of doing it.
I think that having the following query: select count (1) from dvds group by owner would solve this. This is assuming that dvds is your table's name
Use the count function and GROUP BY the column you want to group by.
SELECT OWNER, COUNT(*)
FROM DVD
GROUP BY OWNER
select count(1) as COUNT,OWNER from DVDS group by OWNER
Number of DVDs by owner:
select owner, count(*) from dvd group by owner
Number of unique DVDs by owner:
select owner, count(*)
from (select distinct owner, title from dvd) x
group by owner