Retrieving the most recent entry per user - mysql

If I have a table with the following structure and data:
id | user_id | created_at
-------------------------
1 | 7 | 0091942
2 | 3 | 0000014
3 | 6 | 0000890
4 | 6 | 0029249
5 | 7 | 0000049
6 | 3 | 0005440
7 | 9 | 0010108
What query would I use to get the following results (explanation to follow):
id | user_id | created_at
-------------------------
1 | 7 | 0091942
6 | 3 | 0005440
4 | 6 | 0029249
7 | 9 | 0010108
As you can see:
Only one row per user_id is returned.
The row with the highest created_at is the one returned.
Is there a way to accomplish this without using subqueries? Is there a name in relational algebra parlance that this procedure goes by?

The query is known as a groupwise maximum, which (in MySQL, at least) can be implemented with a subquery. For example:
SELECT my_table.* FROM my_table NATURAL JOIN (
SELECT user_id, MAX(created_at) created_at
FROM my_table
GROUP BY user_id
) t
See it on sqlfiddle.

You can just get the max and group by the user_id:
select id,user_id,max(created_at)
from supportContacts
group by user_id
order by id;
Here is what it outputs:
ID USER_ID MAX(CREATED_AT)
1 7 91942
2 3 5440
3 6 29249
7 9 10108
See the working demo here
Note that the example on the fiddle uses the created_at field as int, just use your format it should make no difference.
EDIT: I will leave this answer as a referece but note that his query will produce undesired results as Gordon stated, please do not use this in production.

Related

Sum of Counted records that calculated using "group by" with condition and "group by"

I'm sorry for fuzzy title of this question.
I have 2 Tables in my database and want to count records of first_table using "group by" on a foreign key id that exists in a column of second_table (which stores ids like array "1,2,3,4,5").
id | name | fk_id
1 | john | 1
2 | mike | 1
3 | jane | 2
4 | tailor | 1
5 | jane | 3
6 | tailor | 5
7 | jane | 4
8 | tailor | 5
9 | jane | 5
10 | tailor | 5
id | name | fk_ids | s_fk_id
1 | xxx | 1,5,6 | 1
2 | yyy | 2,3 | 1
3 | zzz | 9 | 1
4 | www | 7,8 | 1
Now i wrote the following query but it not working properly and displays wrong numbers.
I WANT TO:
1-Count records in first_table group by "fk_id"
2-Sum the counted records which exists in "fk_ids"
3-Display the sum result (sum of related counts) grouped by id.
symbol ' ' means ``.
select sum(if(FIND_IN_SET('fk_id', 'fk_ids')>0,'count',0) 'sum', 'count', 'from'.'fk_id', 'second_table'.* FROM 'second_table'
LEFT JOIN
(
SELECT 'fk_id', count(*) 'count'
FROM 'first_table'
group BY 'fk_id'
) AS 'from'
ON FIND_IN_SET('fk_id', 'fk_ids')>0
WHERE 'second_table'.'s_fk_id'=1
GROUP BY 'id'
ORDER by 'count' DESC
This table has many data and we have no plan to change the structure.
Edit:
Desired output:
id | name | sum
1 | xxx | 7 (3+4+0)
2 | yyy | 2 (1+1)
3 | zzz | 0 (0)
4 | www | 0 (0+0)
After two holidays i came back to work and found out that the "FIND_IN_SET" function is not working properly with space contained string.
And the problem is that i was ignored the spaces too, (same as this question)
Finnaly this query worked:
select sum(`count`) `sum`, `count`, `from`.`fk_id`, `second_table`.* FROM `second_table`
LEFT JOIN
(
SELECT `fk_id`, count(*) `count`
FROM `first_table`
group BY `fk_id`
) AS `from`
ON FIND_IN_SET(`fk_id`, replace(`fk_ids`,' ',''))>0
WHERE `second_table`.`s_fk_id`=1
GROUP BY `id`
ORDER by `count` DESC
And the magic is replace(fk_ids,' ','')

MySQL 5.7 - how to get id for a max value and group by query? [duplicate]

This question already has answers here:
SQL select only rows with max value on a column [duplicate]
(27 answers)
Closed 5 years ago.
I work on MySQL 5.7, I want to get the ID and TITLE of the last article for each category. For example I have the following table 'Article':
| ID | TITLE | DATE | FK_CATEGORY |
| 1 | title 1 | 2016-10-05 | 1 |
| 2 | title 2 | 2017-10-02 | 1 |
| 3 | title 3 | 2015-10-10 | 2 |
| 4 | title 4 | 2017-04-20 | 2 |
| 5 | title 5 | 2017-04-12 | 3 |
For this example I expect the result to be:
| 2 | title 2 | 2017-10-02 | 1 |
| 4 | title 4 | 2017-04-20 | 2 |
| 5 | title 5 | 2017-04-12 | 3 |
I have tryed this request but it does not work :
SELECT id, title, MAX(date), fk_category
FROM article
GROUP BY fk_category
ORDER BY date DESC
What query do I have to use ?
PS: I do not want to disable ONLY_FULL_GROUP_BY SQL mode
Even if you were to disable MySQL's ONLY_FULL_GROUP_BY mode, and your current query were to run, it might not yield the correct results. Also, you would not be able to port the query to most other databases. A better approach is to use a subquery which finds the most recent date for each category. Then, join article to this subquery to get the result set you want.
SELECT t1.*
FROM article t1
INNER JOIN
(
SELECT FK_CATEGORY, MAX(DATE) AS MAX_DATE
FROM article
GROUP BY FK_CATEGORY
) t2
ON t1.FK_CATEGORY = t2.FK_CATEGORY AND
t1.DATE = t2.MAX_DATE
ORDER BY date DESC
The only way is to join the table back, something like:
select a.id, a.date, a.title, a.fk_category
from article a
join
(
SELECT id, MAX(date) as date, fk_category
FROM article
GROUP BY fk_category
) x using (id, date, fk_category)
ORDER BY a.date DESC;

MySQL Order by before group by in view (No Sub-Querys)

I realize this question has been asked quite a few times, however i haven't managed to find a working solution for my case.
Essentially my problem arises because MySQL Doesn't allow sub-querys in views.
I found a few workarounds but they don't seem to work.
In more detail...
My first table (competitions) stores a users competitions:
id_tournament | id_competition | id_user | result
-------------------------------------------------
1 | 1 | 1 | 10
1 | 1 | 2 | 30
1 | 2 | 1 | 20
1 | 2 | 3 | 50
1 | 3 | 2 | 90
1 | 3 | 3 | 100
1 | 3 | 4 | 85
In this example there are three competitions:
(
user1 vs. user2,
user1 vs. user3,
user2 vs. user3 vs. user4
)
My problem is that i need to define a view that gives me the winners in each competition.
Expected Result:
id_tournament | id_competition | id_winner
------------------------------------------
1 | 1 | 2
1 | 2 | 3
1 | 3 | 3
This can be solved with the query:
SELECT
id_tournament,
id_competition,
id_user as id_winner
FROM (
SELECT * FROM competitions ORDER BY result DESC
) x GROUP BY id_tournament, id_competition
This query however uses a subquery (not allowed in views), so my first solution was to define a 'helper view'as :
CREATE VIEW competitions_helper AS (
SELECT * FROM competitions ORDER BY result DESC
);
CREATE VIEW competition_winners AS (
SELECT
id_tournament,
id as id_competition,
id_user as winner
FROM competitions_helper GROUP BY id_tournament, id_competition
);
However this does not seem to give the correct result.
It's result will then be:
id_tournament | id_competition | id_winner
------------------------------------------
1 | 1 | 1
1 | 2 | 1
1 | 3 | 1
What i don't understand is why it works when i use Sub-querys and why it gives a different result with the exact same statement in a view.
Any help is appreciated, thanks alot.
This is due to the GROUP BY behaviour.
In this case, the server is free to choose any value from each group, so unless they are the same, the values chosen are indeterminate, which is probably not what you want.
I would solve the problem in this way:
CREATE VIEW competitions_helper AS (
SELECT id_tournament,
id_competition,
MAX(result) as winning_result
FROM competitions
GROUP BY id_tournament,
id_competition
);
CREATE VIEW competition_winners AS (
SELECT c.id_tournament,
c.id_competition,
c.id_user
FROM competitions c
INNER JOIN competitions_helper ch
ON ch.id_tournament = c.id_tournament
AND ch.id_competition = c.id_competition
AND ch.winning_result = c.result
);

MySQL query to find duplicate having more than (n) entries

I am having troubles with creating up this sql query to find records having more than (n) entries [n=1] in example
I have table
|--id-|--user_id--|
| 1 | 1 |
| 2 | 1 |
| 3 | 1 |
| 4 | 2 |
| 5 | 2 |
| 6 | 3 |
want to retrieve duplicates in my table
|--id-|--user_id--|
| 2 | 1 |
| 3 | 1 |
| 5 | 2 |
any help is very much appreciated, thanks for reading though
UPDATE:
I am using Mysql v5.1
This would be my approach
SELECT ID, USER_ID
FROM TABLE
GROUP USER_ID
HAVING COUNT(1) > 1
MINUS
SELECT MIN(ID) ID, USER_ID
FROM TABLE
GROUP BY USER_ID
EDIT: oops, didn't see that you're using MySQL. you might be able to tweak this query to get it working in MySQL
not sure which version of SQL your using but here's the sqlserver answer:
SELECT * from [table_name] GROUP BY user_id HAVING COUNT(*) > n

mysql Select question

I can't get on the right track with this, any help would be appreciated
I have one table
+---+----------+---------+-----------+
|id | match_id | team_id | player_id |
+---+----------+---------+-----------+
| 1 | 9 | 10 | 5 |
| 2 | 9 | 10 | 7 |
| 3 | 9 | 10 | 9 |
| 4 | 9 | 11 | 12 |
| 5 | 9 | 11 | 15 |
| 6 | 9 | 11 | 18 |
+---+----------+---------+-----------+
I want to select these with a where on the match_id and both team id's so the output will be
+---------+-------+------+---------+---------+
| MATCHID | TEAMA | TEAMB| PLAYERA | PLAYERB |
+---------+-------+------+---------+---------+
| 9 | 10 | 11 | 5 | 12 |
| 9 | 10 | 11 | 7 | 15 |
| 9 | 10 | 11 | 9 | 18 |
+---------+-------+------+---------+---------+
It's probably very simple, but i'm stuck..
thanks in advance
p.s. seemed to forgot a column on my first post, sorry
I think you should redesign your table though, maybe the format that you want as output should be your table design.
With your design, it's possible to have three or more teams playing against each other...
So. I gave this another try (coming from Oracle myself, I really miss ROWNUM here).
The following query should give you the result you want to have, but I'm not sure if you should really do that in pure SQL. Maybe you could just combine the teams in your client?
SELECT m1.match_id, m1.team_id, m2.team_id, m1.player_id, m2.player_id
FROM (
SELECT match_id, team_id, player_id,
-- get ranking
( SELECT 1 + count(*)
FROM matches m1b
WHERE m1b.match_id = m1a.match_id
AND m1b.team_id = m1a.team_id
AND m1b.player_id < m1a.player_id) rank
FROM matches m1a
WHERE m1a.team_id = (SELECT MIN(team_id) -- first team
FROM matches
WHERE match_id = m1a.match_id)
) m1,
(
SELECT match_id, team_id, player_id,
-- get ranking
( SELECT 1 + count(*)
FROM matches m2b
WHERE m2b.match_id = m2a.match_id
AND m2b.team_id = m2a.team_id
AND m2b.player_id < m2a.player_id) rank
FROM matches m2a
WHERE m2a.team_id = (SELECT MAX(team_id) -- second team
FROM matches
WHERE match_id = m2a.match_id)
) m2
WHERE m1.match_id = m2.match_id
AND m1.rank = m2.rank
What I do here is:
Select all ROWs from the teams with lower team_id per match and give them a ranking (1 to 3 per match)
Select all ROWs from the teams with higher team_id per match and give them a ranking (1 to 3 per match)
Combine those two queries in one result, where the match_id and the ranking match
match is a reserve word in mysql. table name used here is matchs
select match_id, sum(if(id=1, team_id,0))team_A, sum(if(id=2,team_id,0)) team_b
from matchs
group by match_id;
+----------+--------+--------+
| match_id | team_A | team_b |
+----------+--------+--------+
| 5 | 9 | 10 |
+----------+--------+--------+
1 row in set (0.00 sec)
I'm not sure if the previous answers will give you what you're looking for, at least I took your question to mean something else - perhaps you could clarify the purpose of the table and the query. If the table associates teams with matches and you want a query to show you all the teams associated with one match, then your query should be
select team_id as teams from table where match_id = id_here
which would give you back (for id_here being 5)
teams
-----
9
10
Take a look at the url below, It is exactly what you want but is in t-sql. It can merge any number of rows.
Converting fields into columns