Sorted data in groups - mysql

Dataset:
id uid activity postid
1 20 A 1
2 20 A 1
3 6 A 1
4 3 A 1
5 6 A 1
6 13 A 1
7 13 B 1
8 18 B 1
9 18 B 1
10 1 A 1
Current Results:
id uid uid_list groupCount activity postid
9 18 18,13 3 B 1
1 20 1,13,6,3,20 7 A 1
Expected Results:
id uid uid_list groupCount activity postid
9 18 18,13 3 B 1
10 1 1,13,6,3,20 7 A 1
The query I have:
SELECT
id,
uid,
GROUP_CONCAT(DISTINCT uid ORDER BY id DESC) as uid_list,
COUNT(*) as groupCount,
activity,
postid
FROM (
SELECT *
FROM `user_activities`
ORDER BY id DESC) as tbl
GROUP BY
activity, postid
ORDER BY
id DESC
I want to group by activity and postid while having the result in descending order by id. And want to have the latest id and uid for every group. I don't understand why this query doesn't return the expected output.

From what I understand id value is increasing. To get the latest values you could use an aggregate function MAX().
Also, your inner query with ordering is unnecessary because the engine has to sort the resultset by id anyways when building result for GROUP_CONCAT().
To retrieve uid for a particular id column you need to self join to the same table.
SELECT
a.id, b.uid, a.uid_list, a.groupcount, a.activity, a.postid
FROM (
SELECT
MAX(id) as id,
GROUP_CONCAT(DISTINCT uid ORDER BY id DESC) as uid_list,
COUNT(*) as groupCount,
activity,
postid
FROM user_activities a
GROUP BY
activity, postid
) a
INNER JOIN user_activities b ON a.id = b.id

Probably the simplest method is the group_concat()/substring_index() trick:
SELECT MAX(ID) as id,
SUBSTRING_INDEX(GROUP_CONCAT(uid ORDER BY ID DESC), ',', 1) as uid,
GROUP_CONCAT(DISTINCT uid ORDER BY id DESC) as uid_list,
COUNT(*) as groupCount,
activity, postid
FROM user_activities ua
GROUP BY activity, postid
ORDER BY id DESC;
There are some limitations to this approach, in the sense that GROUP_CONCAT() has a maximum length for the intermediate value. Typically the default is sufficient, but you might need to change that value if many, many rows match each group (and you already have this issue for the list of uids anyway).

Related

Finding rows with latest date by id mysql

I have these 2 tables I am trying to write a query that will help me select all rows that gives this result
users
id
name
1
test
2
test2
logs
id
userId
message
date
1
1
this is a test
2020-10-07 12:57:14
2
1
another reason
2020-10-07 13:57:14
3
1
another reason 2
2020-10-07 14:57:14
4
2
another reason 3
2020-10-04 12:57:14
5
2
another reason 4
2020-10-05 12:57:14
6
2
another reason 4
2020-10-06 12:57:14
Output Table
I need to pass many user Ids like in this case (1,2) and get below table only return MAX (date) per row per userId
id
userId
message
date
3
1
another reason 2
2020-10-07 14:57:14
6
2
another reason 4
2020-10-06 12:57:14
Is this possible with one Query? This what I have but not working
SELECT
id ,
userId ,
message,
date
FROM logs
WHERE userId IN (1,2)
ORDER BY date DESC;
You may use the results of a window function ROW_NUMBER to retrieve these results.
SELECT
id,userId,message,date
FROM (
SELECT
*,
ROW_NUMBER() OVER (
PARTITION BY userId
ORDER BY date DESC
) as rn
FROM
logs
) t
WHERE rn=1 AND
userId IN (1,2)
ORDER BY date DESC
and for older mysql versions
SELECT
id,userId,message,date
FROM (
SELECT
l.*,
#row_num:=IF(userId=#prev_user_id,#row_num+1,1) as rn,
#prev_user_id:=userId
FROM
logs l
CROSS JOIN (
SELECT #row_num:=0, #prev_user_id:=NULL
) as vars
ORDER BY userId, date DESC
) t
WHERE rn=1 AND
userId IN (1,2)
ORDER BY date DESC

Another distinct and limit mysql

The following does what it supposed to
it returns 200+ distinct records w/o the "limit 2"
What I want is to return 2 distinct records, but it stops after the 1st 2 records, meaning I only get 2 records
select distinct LEFT(`name`, LOCATE("(", `name`)-1), user_id, id
from ppbv79_listings
where user_id = 3798 and category_id = 30
group by LEFT(`name`, LOCATE("(", `name`)-1)
limit 2
Name user_id id
Germany 1213 Used Carl Sonnenschein 3798 2160555
Germany 1213 Used Carl Sonnenschein 3798 2160556
Try this:
select A.`trimmedName`, A.user_id, A.id
from
(select LEFT(`name`, LOCATE("(", `name`)-1)
`trimmedName`, user_id, id,count(category_id) `count`
from ppbv79_listings
where user_id = 3798 and category_id = 30
group by LEFT(`name`, LOCATE("(", `name`)-1), user_id, id
order by `count` desc) A
limit 2;
I assume there are some repetitions you would want to removed, and fetch the just the top 2 rows of data that repeats most.

SQL order by after more than

I am trying SQL to sort results
id | name (table name: student)
-----
1 | jhon
2 | amin
3 | heli
4 | mir
5 | mrs
6 | amr
7 | jonnathan
8 | adhy
When i use this query
select id from studenth where id>='3' order by id DESC limit 2
The result that appears is
id | name (table name: student)
-----
8 | adhy
7 | jonnathan
Whereas I want to sort results after id = 3, I want the data as below
id | name (table name: student)
-----
4 | mir
3 | heli
select * from (select id from student where id >= 3 order by id limit 2) r order by r.id desc
You can use this query. You want everything less than or equal to 4 instead of everything after 3.
select id from student where id<='4' order by id DESC limit 2
You can do some like:
select * from student where id>=3 order by id LIMIT 2
If you want to take the records and sort it in descending order,then you can go for a subquery.
SELECT * FROM
( SELECT *
FROM student
WHERE id>=3 ORDER BY id LIMIT 2) X
ORDER BY X.id DESC
Problem with your Query
select * from student where id>='3' order by id DESC limit 2
The above query will take all the results with id=3 or more and order it in the descending order and with LIMIT 2 it will display only 2 records.
That's why it's displaying the last 2 records.
TRY THIS Use sub query it's easy to understand and fulfill your requirement:
SELECT id, name
FROM studenth
WHERE id IN (SELECT id
FROM studenth
WHERE id >= 3 ORDER BY id LIMIT 2) ORDER BY id DESC
If i understood correctly , you want the data in descending order from id +1 record. the query should be something like below:
select id from studenth where id<='4' order by id DESC limit 2;
Remove single quotes in this id>='3'
select id from student where id>=3 order by id desc limit 2
Update 1:
Order by desc limit 2 problem here use subquery get the result then apply descending .
select * from (select id from student where id >= 3 order by id limit 2) new order by new.id desc
Please try the following...
SELECT id,
name
FROM tblTable
WHERE id >= 3
ORDER BY id DESC
LIMIT ( ( SELECT COUNT( * )
FROM tblTable
WHERE id >= 3 ) - 1 ), 2;
This statement works by sorting the records from tblTable based on the value of id. It then uses LIMIT to select specific records from the sorted list. If there are 20 eligibnle records this equates to LIMIT 19, 2, which will give us the 19th and 20th records.
If you have any questions or comments, then please feel free to post a Comment accordingly.

MySQL query that selects all users that have more than one entry per day

I want to get all the USER_ID for users who have posted more than one thing per day,
I tried originally tried this
SELECT USER_ID, count(DISTINCT cast(POSTING_DATE as DATE))
AS NUM_DAYS_OF_DUPLICATES FROM POSTING_TABLE
WHERE USER_ID IN
(SELECT USER_ID FROM POSTING_TABLE
GROUP BY CAST(POSTING_DATE AS DATE) HAVING count(*) >= 2)
GROUP BY USER_ID ORDER BY NUM_DAYS_OF_DUPLICATES DESC;
Then this works for a specific USER_ID
SELECT USER_ID FROM POSTING_TABLE WHERE USER_ID = 30
GROUP BY cast(POSTING_DATE AS DATE)
HAVING count(cast(POSTING_DATE AS DATE)) > 1
The above gives me the correct result, however when I run the query on the entire table without specifying a USER_ID it does not.
eg.,
table structure USER_ID, POSTING_DATE ...
USER_ID POSTING_DATE
1 10-10-13
1 10-10-13
1 10-12-13
1 10-12-13
2 10-10-13
2 10-10-13
3 10-10-13
4 10-12-13
Where the result would give me
USER_ID NUM_DAYS_WITH_MORE_THAN_ONE_POSTING
1 2
2 1
3 0
4 0
Also if we can omit the 0's
This is the solution
select x.user_id, count(x.num_days)
from
(
select USER_ID, COUNT(USER_ID) AS NUM_DAYS
from data1
group by user_id, posting_date
having count(user_id) > 1
) x
group by 1
Working SQL Fiddle
(I used a varchar for date for simplicity but it should work fine with date too. You can check with your own database)

Order by top five repeated IDs

There is a table in my database duplicate_id which contains multiple ids and also contains many duplicate ids in it. What I have been trying to do is to sort top five ids which are being repeated the most in the table duplicate_id. Kindly let me know how can i do that
Table Structure: ID | Message
Expected output:
ID | Number of repeats
201 8
212 7
205 5
209 3
229 2
SELECT ID, COUNT(*) AS `Number of repeats`
FROM duplicate_id
GROUP BY ID
ORDER BY COUNT(*) DESC
LIMIT 5
Try the order by so sort your results:
Select * from table order by repeats desc limit 5
well... try this (I don't know mysql, so I have to guess)
select ID,
count(*) as 'Number of Repeats'
from duplicate_ID
group by ID
order by 2
Another approach would be
select ID, 'Number of Repeats'
from (
select ID,
count(*) as 'Number of Repeats'
from duplicate_ID
group by ID
) x
order by 'Number of Repeats'