Get all actions of the last-three users for each post - mysql

In a last Question, i asked about geting all actions of the last three users from a history table that stores all actions done by users on deferments posts, now what i want is to get the same thing but for each post.
all actions of donne by the last-three users for each posts
history table
id | post_id | action | user_id
1 | 5 | 1 | 3
1 | 23 | 2 | 1
2 | 24 | 2 | 6
3 | 34 | 1 | 7
4 | 35 | 1 | 1
5 | 36 | 1 | 1
6 | 23 | 2 | 3
7 | 24 | 2 | 1
8 | 23 | 1 | 4
9 | 24 | 1 | 5
10 | 24 | 1 | 1
11 | 23 | 1 | 2
12 | 23 | 4 | 1
thanks and sorry if it seem to be a duplicate post

I think this will work:
SELECT a.user_ID, a.post_id, a.action
FROM tableName a
INNER JOIN
(
SELECT DISTINCT
#curRow:=IF(#prevRow=post_Id,#curRow+1,1) rn,
user_ID,
Post_Id,
#prevRow:=Post_Id
FROM (
SELECT DISTINCT Post_Id, User_Id
FROM TableName
ORDER BY Post_Id, ID DESC
) t
JOIN (SELECT #curRow:= 0) r
) b ON a.post_id = b.post_id AND a.user_id = b.user_id
WHERE b.rn <= 3
ORDER BY a.post_id, a.User_ID
And the Fiddle.

Coudl this be what you are looking for?
SQLFiddle
Code:
SELECT a.user_ID,
group_concat(a.post_id),
group_concat(a.action)
FROM tableName a
INNER JOIN
(
SELECT DISTINCT user_ID
FROM tableName
ORDER BY ID DESC
LIMIT 3
) b ON a.user_ID = b.user_ID
group by a.user_id
ORDER BY a.User_ID;
| USER_ID | GROUP_CONCAT(A.POST_ID) | GROUP_CONCAT(A.ACTION) |
--------------------------------------------------------------
| 2 | 7 | 3 |
| 3 | 5,5,4 | 1,2,5 |
| 6 | 7 | 2 |

Related

How can I get ids of grouped rows?

I have a table like this:
// notifications
+----+--------+-----------+---------+--------------------+
| id | money | post_id | user_id | belongs_to_user_id |
+----+--------+-----------+---------+--------------------+
| 1 | 5 | 1 | 123 | 101 |
| 2 | 10 | 2 | 123 | 101 |
| 3 | -2 | 4 | 456 | 101 |
| 5 | -2 | 2 | 456 | 101 |
| 6 | -2 | 3 | 123 | 101 |
| 7 | 5 | 4 | 789 | 101 |
| 8 | 10 | 4 | 789 | 101 |
+----+--------+-----------+---------+--------------------+
And here is my query:
SELECT * FROM notifications
WHERE belongs_to_user_id = 101
GROUP BY post_id, user_id
ORDER BY id DESC
LIMIT 3
The current output should be something like this:
+----+--------+-----------+---------+--------------------+
| 5 | -2 | 2 | 456 | 101 |
| 6 | -2 | 3 | 123 | 101 |
| 8 | 10 | 4 | 789 | 101 |
+----+--------+-----------+---------+--------------------+
The seventh row is grouped and we cannot see it in the result. That's exactly the problem. Here is the expected result:
+----+--------+-----------+---------+--------------------+
| 5 | -2 | 2 | 456 | 101 |
| 6 | -2 | 3 | 123 | 101 |
| 7 | 5 | 4 | 789 | 101 |
| 8 | 10 | 4 | 789 | 101 |
+----+--------+-----------+---------+--------------------+
If I remove GROUP BY, then the fifth will be omitted. So here is the logic:
I want to the last three rows (regardless grouping). In other word, Emm ... it's hard to say, I want to select grouped rows (but not counting in LIMIT).
Any idea how can I do that?
It shows comma separated id by groups
SELECT
GROUP_CONCAT(id),
post_id
FROM notifications
WHERE belongs_to_user_id = 101
GROUP BY post_id, user_id
ORDER BY id DESC
LIMIT 3
Please try this query. It will get the last three "groups", and then extract all the rows of those groups (using a join):
SELECT t.*
FROM notifications t
INNER JOIN (SELECT s.post_id, s.user_id
FROM notifications s
WHERE belongs_to_user_id = 101
GROUP BY post_id, user_id
ORDER BY post_id DESC, user_id DESC
LIMIT 3) u
ON u.post_id = t.post_id
AND u.user_id = t.user_id
WHERE t.belongs_to_user_id = 101
ORDER BY t.id
Update: same query using DISTINCT in the subquery:
SELECT t.*
FROM notifications t
INNER JOIN (SELECT DISTINCT s.post_id, s.user_id
FROM notifications s
WHERE belongs_to_user_id = 101
ORDER BY post_id DESC, user_id DESC
LIMIT 3) u
ON u.post_id = t.post_id
AND u.user_id = t.user_id
WHERE t.belongs_to_user_id = 101
ORDER BY t.id
Please try this
SELECT * FROM notifications WHERE belongs_to_user_id = 101 GROUP BY id, money ORDER BY id DESC
So, you want correlation subquery if i am not wrong
select * from table t
where belongs_to_user_id = 101 and
user_id = (select max(user_id) from table where post_id = t.post_id)
Additionally, you could add limit clause to limit the records that you want.

MYSQL Select two tables with multiple which is not there

I try to use LEFT JOIN but I dont get the result I want.
I have 2 tables
Table 1:
Persons
UID | Names | GID
1 | Mike | 1
2 | Tom | 1
3 | Brenda | 1
4 | Sophie | 2
Table 2:
DailyLog
ID | UID | GID | DATE
1 | 1 | 1 | 2017-10-13
2 | 2 | 1 | 2017-10-13
3 | 3 | 1 | 2017-10-13
4 | 1 | 1 | 2017-10-13
5 | 2 | 1 | 2017-10-14
6 | 1 | 1 | 2017-10-14
7 | 1 | 1 | 2017-10-15
I want search a name who is not have a stamp date of today (2017-10-15) in GID 1,
a result like this:
UID | Name
2 | Tom
3 | Brenda
I use SQL Left Join, but the result not what I expected.
SELECT DISTINCT a.uid
, a.Name
, b.date
FROM Persons AS a
LEFT
JOIN dailylog AS b
ON a.uid = b.uid
AND a.gid = b.gid
WHERE (b.date IS NULL OR b.date !='2017-10-15' )
AND a.gid='1'
Thank you
you could use a not In clause
SELECT a.uid
, a.Name
, b.date
FROM Persons
where uid not in (
select uid from DailyLog
where GID = 1
and DATE = '2017-10-15'
)

use standard values if there is no overlap in table columns

I have a table ce_relations and a table ce_values which i want to combine to a table ce_combined_values. The ce_combined_values table should have the exact same amount of rows as ce_relations. The query stated below does however only return the rows where the user_id and friend_id is existing in the ce_values.user_id column. I tried to solve this problem by using the IFNULL statement, but i guess there is also an extra condition missing in the WHERE clausule... any help is welcome!
INSERT INTO ce_combined_values (user_id, friend_id, relation_degree, user_value, friend_value, relation_value)
SELECT a.user_id, a.friend_id, a.relation_degree, IFNULL(b.1d_value, 0) as user_value, IFNULL(c.1d_value, 0) as friend_value, Least(b.1d_value, c.1d_value) as relation_value
FROM ce_relations a, ce_values b, ce_values c
WHERE a.relation_degree = 1 AND b.user_id = a.user_id AND c.user_id = a.friend_id AND b.user_id <> c.user_id
Union all
//same select query is used for relation_degree 2 with 2d_values and relation_degree 3 with 3d_values.
EDIT:
For example this is what I want to achieve:
table ce_relations:
+---------+-----------+-----------------+
| user_id | friend_id | relation_degree |
+---------+-----------+-----------------+
| 1 | 3 | 1 |
| 2 | 1 | 1 |
| 3 | 4 | 1 |
+---------+-----------+-----------------+
table ce_values:
+---------+----------+----------+----------+
| user_id | 1d_value | 2d_value | 3d_value |
+---------+----------+----------+----------+
| 1 | 5 | 10 | 33 |
| 2 | 10 | 12 | 44 |
| 3 | 20 | 13 | 55 |
+---------+----------+----------+----------+
should become ce_combined values ( deleted relation_degree and relation_value for readability)
+---------+-----------+------------+--------------+
| user_id | friend_id | user_value | friend_value |
+---------+-----------+------------+--------------+
| 1 | 3 | 5 | 20 |
| 2 | 1 | 10 | 5 |
| 3 | 4 | 20 | 0 |
+---------+-----------+------------+--------------+
but currently returns ( the row with friend_id = 4 is missing because it doesn't exist in ce_values)
+---------+-----------+------------+--------------+
| user_id | friend_id | user_value | friend_value |
+---------+-----------+------------+--------------+
| 1 | 3 | 5 | 20 |
| 2 | 1 | 10 | 5 |
+---------+-----------+------------+--------------+
If I understand your problem correctly, you need to LEFT JOIN your tables. And I don't think you need to UNION ALL the same query three times with just a different filter condition.
Maybe that helps you:
SELECT a.user_id, a.friend_id, a.relation_degree,
IFNULL(b.value, 0) as user_value,
IFNULL(c.value, 0) as friend_value,
Least(b.value, c.value) as relation_value
FROM ce_relations a
LEFT
JOIN ce_values b
ON a.user_id = b.user_id
LEFT
JOIN ce_values c
ON a.friend_id = c.user_id
AND b.user_id <> c.user_id
WHERE a.relation_degree IN (1, 2, 3)

SQL Statement Construction: Selecting Unique Records

I currently have a table of Users, and at what time they connected to a device (e.g. a Wifi Router).
+-------------+-----------+---------+------------+---------------------+
| location_id | device_id | user_id | dwell_time | date |
+-------------+-----------+---------+------------+---------------------+
| 14 | 1 | 1 | 27.000000 | 2014-01-04 00:51:12 |
| 15 | 2 | 1 | 12.000000 | 2014-01-04 01:08:56 |
| 16 | 1 | 1 | 12.000000 | 2014-01-04 01:09:26 |
| 17 | 2 | 1 | 318.000000 | 2014-01-04 01:09:38 |
| 18 | 1 | 2 | 20.000000 | 2014-01-04 01:30:03 |
| 19 | 2 | 3 | 20.000000 | 2014-01-04 01:30:03 |
+-------------+-----------+---------+------------+---------------------+
I need to write a query title "Get Latest User Connections".
Basically, it needs to go through the history table shown above, and pick the latest record (based on Date) for each user and display it. In the example above, the result should be:
+-------------+-----------+---------+------------+---------------------+
| location_id | device_id | user_id | dwell_time | date |
+-------------+-----------+---------+------------+---------------------+
| 17 | 2 | 1 | 318.000000 | 2014-01-04 01:09:38 |
| 18 | 1 | 2 | 20.000000 | 2014-01-04 01:30:03 |
| 19 | 2 | 3 | 20.000000 | 2014-01-04 01:30:03 |
+-------------+-----------+---------+------------+---------------------+
Can someone please help me write a SQL statement that does this?
Assuming the combination of user_id and date is unique in the table, you could
SELECT
tablename.*
FROM tablename
INNER JOIN (
SELECT user_id, MAX(`date`) AS maxdate
FROM tablename
GROUP BY user_id
) AS selector
ON tablename.user_id=selector.user_id AND tablename.`date`=selector.maxdate
select *
from users
inner join (select user_id,max(date) as maxdate
from users
group by user_id)T1
on T1.user_id = users.user_id
AND T1.maxdate = users.date
or if you don't want to have a subquery, you can user #variables like this query below
SELECT location_id,device_id,user_id,dwell_time,date,
IF(#prevUserId IS NULL OR #prevUserId != user_id,#row:=1,#row:=#row+1) as row,
#prevUserId := user_id
FROM users
HAVING row = 1
ORDER BY user_id,date DESC
here's the sqlFiddle
Try this:
SELECT u.location_id, u.device_id, u.user_id, u.dwell_time, u.datec
FROM (SELECT u.location_id, u.device_id, u.user_id, u.dwell_time, u.date
FROM users u ORDER BY u.user_id, u.date DESC
) A
GROUP BY u.user_id
OR
SELECT u.location_id, u.device_id, u.user_id, u.dwell_time, u.date
FROM users u
INNER JOIN (SELECT u.user_id, MAX(u.date) AS latestDate
FROM users u GROUP BY u.user_id
) A ON u.user_id = A.user_id AND A.latestDate = u.date

Get max paired users scores with min time sums

I have MySQL tables that look like this
users
user_id | partner_id | name
--------+------------+-----
1 | 2 | aaa
2 | 1 | bbb
3 | 4 | ccc
4 | 3 | ddd
games
game_id | user_id
--------+--------
1 | 1
2 | 1
3 | 2
4 | 3
5 | 4
6 | 4
scores
game_id | level | score | time
--------+-------+-------+-----
1 | 1 | 1 | 10
1 | 2 | 1 | 10
1 | 3 | 1 | 10
2 | 1 | 0 | 20
2 | 2 | 0 | 20
2 | 3 | 0 | 20
3 | 1 | 1 | 30
3 | 2 | 1 | 30
3 | 3 | 1 | 30
4 | 1 | 1 | 2
4 | 2 | 1 | 2
4 | 3 | 1 | 2
5 | 1 | 1 | 5
5 | 2 | 1 | 5
5 | 3 | 1 | 5
6 | 1 | 1 | 3
6 | 2 | 1 | 3
6 | 3 | 0 | 3
And i need to query it so it sums points and time per game, so it looks like this
game_id | user_id | sumPoints | sumTime
--------+---------+-----------+--------
1 | 1 | 3 | 30
2 | 1 | 0 | 60
3 | 2 | 3 | 90
4 | 3 | 3 | 6
5 | 4 | 3 | 15
6 | 4 | 2 | 9
And then i need to get best scores per pair (where it takes better score of one user), so it looks like this:
user1_id | user2_id | sumPoints | sumTime
---------+----------+-----------+--------
3 | 4 | 3 | 6
1 | 2 | 3 | 30
That's the final result. I'd really appreciate if someone could show me how it should looks like as sql query.
I'd like to mention that first part is solved by JW 웃 in this post
Thanks in advance.
Something like this should work (this answers your second query)
SELECT
user_details.user_id,
user_details.partner_id,
score_details.score,
score_details.time
FROM
( SELECT
min(user_id) as user_id,
max(user_id) as partner_id
FROM
users
GROUP BY
user_id + partner_id ) AS user_details
JOIN
( SELECT
scores.game_id ,
games.user_id,
sum(score) score,
sum(time) time,
#row_num := IF(#prev_value=games.user_id,#row_num+1,1) AS row_num,
#prev_value := games.user_id
FROM
scores
inner join games on games.game_id = scores.game_id
inner join users on users.user_id = games.user_id
GROUP BY
scores.game_id
ORDER BY
user_id,
score
) as score_details ON ( score_details.user_id = user_details.user_id AND score_details.row_num = 1)
The first part of JOIN gets the users along with their partners, users appearing first within their pair are displayed first, eg: if there are 2 users with ID 1 and 2 I consider the user_id of user 1 as he appears first within his pair.
The second query is based on "echo_me" answer along with a row_number that specifies the ranking of the scores for each user, the highest score has the rank as 1 for every user.
SQLFIDDLE
Hope this is helpful
try this
select scores.game_id ,games.user_id,sum(score) score, sum(time) time
from scores
inner join games
on games.game_id = scores.game_id
inner join users
on users.user_id = games.user_id
group by scores.game_id
DEMO HERE
for the best score
select users.user_id as user1_id,users.partner_id as user2_id,sum(score) score, sum(time) time
from scores
inner join games
on games.game_id = scores.game_id
inner join users
on users.user_id = games.user_id
group by scores.game_id
order by sum(time) asc limit 1
DEMO HERE
OUTPUT.
USER1_ID USER2_ID SCORE TIME
1 2 3 30