I want to get the unique data from multiple tables with the highest id
Refer below data
Users Table
id firstname_english
------ --------------------
2 Lama
4 Akram
6 Ammar
8 Basil
10 Sami
12 Hasan
14 Adnan
16 Mamoon
18 Sulaiman
20 Wasfi
22 Mervat
Users form status with their id
id users_id status_id
------ ----------- -----------
3 2 10
368 4 10
5 4 10
402 6 9
7 6 10
9 8 10
11 10 10
223 10 10
13 12 10
3253 14 2
15 14 10
17 16 10
1488 16 9
231 16 10
19 18 10
22 20 10
750 20 9
232 22 10
24 22 10
2935 22 9
297 22 10
The Result I need
id firstname_english status_id form_id
------ -------------------- --------------------
2 Lama 10 3
4 Akram 10 368
6 Ammar 9 402
8 Basil 10 8
10 Sami 10 223
12 Hasan 10 12
........and so on
I need to display the highest data from the table 2 with the matching id of table 1
For MySql 8.0+ use row_number() window function:
select
u.id, u.firstname_english,
f.status_id, f.id form_id
from users u inner join (
select *,
row_number() over (partition by users_id order by id desc) rn
from users_form
) f on f.users_id = u.id
where f.rn = 1
See the demo.
For previous versions of MySql:
select
u.id, u.firstname_english,
f.status_id, f.id form_id
from users u inner join (
select uf.* from users_form uf
where not exists (
select 1 from users_form
where users_id = uf.users_id and id > uf.id
)
) f on f.users_id = u.id
See the demo.
Results:
| id | firstname_english | status_id | form_id |
| --- | ----------------- | --------- | ------- |
| 2 | Lama | 10 | 3 |
| 4 | Akram | 10 | 368 |
| 6 | Ammar | 9 | 402 |
| 8 | Basil | 10 | 9 |
| 10 | Sami | 10 | 223 |
| 12 | Hasan | 10 | 13 |
| 14 | Adnan | 2 | 3253 |
| 16 | Mamoon | 9 | 1488 |
| 18 | Sulaiman | 10 | 19 |
| 20 | Wasfi | 9 | 750 |
| 22 | Mervat | 9 | 2935 |
Related
I'm curious if is that possible to do similar query using CTE (the values of "id" may vary, not necessarily in succession)
SELECT
elt((#mxId := if(#mxId + 1 <= 3, #mxId + 1, 1)), 5, 10, 22, 33) val,
id
FROM my_table
INNER JOIN (SELECT #mxId := 0) tmp;
Expected output:
val | id
-----+----
5 | 1
10 | 2
22 | 3
5 | 4
10 | 5
22 | 6
5 | 7
10 | 8
22 | 9
5 | 10
10 | 11
22 | 12
5 | 13
10 | 14
22 | 15
5 | 16
10 | 17
22 | 18
5 | 19
10 | 20
with my_table_numbered as (
select ((row_number() over ())-1)%3 as rn_mod, id from my_table
)
select elt(rn_mod+1, 5, 10, 22, 33) as val, id
from my_table_numbered;
Output:
+------+----+
| val | id |
+------+----+
| 5 | 1 |
| 10 | 2 |
| 22 | 3 |
| 5 | 4 |
| 10 | 6 |
| 22 | 7 |
| 5 | 8 |
| 10 | 9 |
| 22 | 13 |
| 5 | 14 |
| 10 | 15 |
| 22 | 16 |
+------+----+
You should specify an ORDER BY in the CTE to get a meaningful and reliable row numbering, but you didn't have one in the query in your question.
row_number() OVER ()
that's do the magic - Thanks very much
I am trying to create an query that results in unique identifiers (account number).
What I need to achieve is for each unique entry into Col1 to create a another row number / UI.
I have been attempting this with the below query
elect col1,col2 ,(DENSE_RANK() OVER( ORDER BY col1,col2)) as UI from [TABLE]
and this is what i have been getting:
col1 col2 UI
34 1 1
1973 448 2
355 3924 3
18709 8168 4
5201 9211 5
5762 9294 6
3864 10669 7
4914 12568 8
4914 12569 9
42465 921 10
but i need it to look like this:
col1 col2 UI
34 1 1
1973 448 2
355 3924 3
18709 8168 4
5201 9211 5
5762 9294 6
3864 10669 7
4914 12568 8
4914 12569 8
42465 921 9
You need to define a way to - more loosely - rank col2 e.g. using division
select
col1,col2
,DENSE_RANK() OVER( ORDER BY col1,col2/10) as newUI
from mytable
+----+-------+-------+-------+
| | col1 | col2 | newUI |
+----+-------+-------+-------+
| 1 | 34 | 1 | 1 |
| 2 | 355 | 3924 | 2 |
| 3 | 1973 | 448 | 3 |
| 4 | 3864 | 10669 | 4 |
| 5 | 4914 | 12568 | 5 |
| 6 | 4914 | 12569 | 5 |
| 7 | 5201 | 9211 | 6 |
| 8 | 5762 | 9294 | 7 |
| 9 | 18709 | 8168 | 8 |
| 10 | 42465 | 921 | 9 |
+----+-------+-------+-------+
I've got those tables
table1: GROUPS
grpID | name
--------------
1 | A
2 | B
3 | C
4 | D
5 | E
table2: USERS
userID | grpID | name
----------------------
1 |1 | nick
2 |1 | john
3 |1 | florans
4 |1 | keit
5 |1 | maria
6 |2 | ian
7 |2 | george
8 |2 | peter
9 |2 | bill
10 |2 | jonathan
11 |3 | jenifer
12 |3 | mina
13 |3 | ben
14 |3 | nick
15 |3 | john
16 |4 | florans
17 |4 | keit
18 |4 | maria
19 |4 | ian
20 |4 | george
21 |5 | peter
22 |5 | bill
23 |5 | jonathan
24 |5 | jenifer
25 |5 | mina
table3:POSTS
userID | posts
--------------
1 | 14
2 | 65
3 | 3
4 | 65
5 | 98
6 | 37
7 | 81
8 | 13
9 | 22
10 | 74
11 | 88
12 | 31
13 | 37
14 | 64
15 | 1
16 | 76
17 | 50
18 | 39
19 | 69
20 | 42
21 | 17
22 | 56
23 | 89
24 | 53
25 | 20
MySQL Fiddle
My goal is to get AVG (average) of the first 3 higher rows from every group. (or SUM of (max1, max2, max3) / 3 ).
Something like this:
grpID | max1 | max2 | max3 | AVG of max1, max2, max3
---------------------------------------------------------
1 98 65 65 76
5 89 56 53 66
4 76 69 50 65
2 81 74 37 64
3 88 64 37 63
and display it ORDER BY first 3 average DESC.
The final result will be like this:
grpID | first 3 higher rows Average
---------------------------------
1 |76
5 |66
4 |65
2 |64
3 |63
What i tried: (*** edited after Strawberry's comment)
SELECT GROUPS.grpID, GROUPS.name, AVG(POSTS.posts) AS PostsAVG
FROM USERS
INNER JOIN POSTS ON POSTS.userID = USERS.userID
INNER JOIN GROUPS ON GROUPS.grpID = USERS.grpID
GROUP BY GROUPS.grpID
ORDER BY PostsAVG DESC
The result i am getting with this is
grpID | name | PostsAVG
--------------------------------
4 | D | 55.2000
1 | A | 49.0000
5 | E | 47.0000
2 | B | 45.4000
3 | C | 44.2000
How can i get only the first three rows and not all 5 rows Average?
Can anyone help to solve this?
You could make use of variables to number the records in order of descending posts, per group. And then you could filter those on that row number ( < 4 ) to finally average those per group:
select grpid, avg(posts) as postavg
from ( select #rn := if(#grpid = grpid, #rn+1, 1) as rn,
#grpid := grpid as grpid,
posts
from ( select grpid, posts
from users1
inner join posts1
on posts1.userid = users1.userid
order by grpid, posts desc
) ordered,
( select #grpid := 0, #rn := 1) init
) numbered
where rn < 4
group by grpid;
http://rextester.com/HWR28741
Without variables
Without variables (and without the availability of window functions), you'd probably do best to create a function for this:
create function GetAveragePosts (grpid int)
returns float
return (select avg(posts)
from ( select posts
from users
inner join posts
on posts.userid = users.userid
where users.grpid = grpid
order by posts desc
limit 3
) topthree
);
And then the SQL itself is straightforward:
select grpid,
GetAveragePosts(grpid) as postsavg
from users
group by grpid
order by 2 desc
MySql fiddle outputs:
| grpID | postsavg |
|-------|----------|
| 1 | 76 |
| 5 | 66 |
| 4 | 65 |
| 2 | 64 |
| 3 | 63 |
course_completions
+-----------------------------------------------+
| id coursemodid userid state timemodified |
+-----------------------------------------------+
| 370 23 2 1 1433582890 |
| 329 24 89 1 1427771915 |
| 333 30 39 1 1428309816 |
| 332 32 39 1 1428303307 |
| 327 33 40 1 1427689703 |
| 328 34 89 1 1427710711 |
| 303 35 41 1 1410258482 |
| 358 36 99 1 1432020067 |
| 365 25 2 1 1433142455 |
| 304 26 69 1 1410717866 |
| 353 37 95 1 1430387005 |
| 416 38 2 1 1438972465 |
| 300 27 70 1 1409824001 |
| 302 29 74 1 1412055704 |
| 297 30 2 1 1409582123 |
| 301 133 41 1 1410255923 |
| 336 133 91 1 1428398435 |
| 364 133 40 1 1433142348 |
| 312 133 85 1 1425863621 |
+-----------------------------------------------+
course_modules
+------------------+
| id course |
+------------------+
| 23 6 |
| 24 6 |
| 25 6 |
| 26 6 |
| 27 6 |
| 28 6 |
| 29 8 |
| 30 8 |
| 31 8 |
| 32 8 |
| 33 8 |
| 34 5 |
| 35 5 |
| 36 5 |
| 37 5 |
| 38 5 |
| 39 9 |
| 40 9 |
| 41 9 |
+------------------+
course_mod_settings
+--------------------------------------+
|id course modinstance |
+--------------------------------------+
| 27 8 30 |
| 28 8 31 |
| 29 8 32 |
| 30 8 33 |
| 31 6 23 |
| 32 6 24 |
| 33 6 25 |
| 34 6 26 |
| 35 6 27 |
| 36 6 28 |
| 37 9 39 |
| 38 9 40 |
| 39 9 41 |
+--------------------------------------+
I was trying about to frame two sub queries in one SQL statement like I want the count of 'criteria mod settings' table values in one column and count of 'course_completions' table values in one column for a particular user along with course.
There shouldn't be relation between count(cms.id) and count(cc.id) except course id, because count(cms.id) is the count of user modules and count(cc.id) is the settings count set by default.
OUTPUT:
COURSE USERID count(cms.id) count(cc.id)
6 89 3 6
6 39 7 6
6 40 5 6
8 69 3 4
8 2 0 4
8 95 4 4
COURSE : getting courseid
USERID : getting userid
count(cms.id) : getting the count of user completed modules.
count(cc.id) : getting the count of settings (ex: For course 6, settings count has 6 and for course 4, settings count has 3.
SELECT cm.course
,cc.userid
,count(cc.coursemodid) AS usermodules
,(
SELECT count(ccc.id)
FROM course_mod_settings cms
INNER JOIN course_modules cm ON cms.course = cm.course
) AS modsettings
FROM course_completions cc
INNER JOIN course_modules cm ON cc.coursemodid = cm.id
WHERE cc.STATE = 1
GROUP BY cm.cours
,cc.userid
I have read your comment above.
Have you tried something like this?
I didn't test the query, it's just a thought.
I might be wrong.
SELECT cms.course AS COURSE, cc.userid AS USERID, COUNT(cms.id), COUNT(cc.id) FROM
course_completions AS cc
INNER JOIN course_modules AS cm ON cc.coursemodid = cm.id
INNER JOIN course_mod_settings AS cms cm.course = cms.course
WHERE cc.state = 1
GROUP BY cm.course, cc.userid
I know this type of question has been asked multiple times but I am not able to find a good answer of my question.
I tried to fetch top 3 viewed records of every person from the table.
mytable
id user_id views
1 5 6
2 5 3
3 6 5
4 7 4
5 9 14
6 5 3
7 5 8
8 6 7
9 7 15
10 9 13
11 9 13
12 9 18
13 6 8
14 8 0
result
id user_id views
12 9 18
9 7 15
5 9 14
10 9 13
13 6 8
7 5 8
8 6 7
1 5 6
3 6 5
4 7 4
2 5 3
14 8 0
I followed this link http://www.xaprb.com/blog/2006/12/07/how-to-select-the-firstleastmax-row-per-group-in-sql/
My Query
select *
from mytable
where (
select count(*) from mytable as f
where f.user_id = mytable.user_id and f.views >= mytable.views
) < 4 order by user_id desc;
But this query is not fetching those records where views are equal.
Please point me to the right direction.
Try this:
SELECT id, user_id, views
FROM (SELECT IF(#lastUserId = #lastUserId:=t.user_id, #ID:=#ID+1, #ID:=1) AS userNo,
t.id, t.user_id, t.views
FROM mytable t, (SELECT #ID:=0, #lastUserId:=0) A
ORDER BY t.user_id, t.views DESC
) AS A
WHERE userNo <= 3
ORDER BY views DESC
Check the SQL FIDDLE DEMO
OUTPUT
| ID | USER_ID | VIEWS |
|----|---------|-------|
| 12 | 9 | 18 |
| 9 | 7 | 15 |
| 5 | 9 | 14 |
| 10 | 9 | 13 |
| 7 | 5 | 8 |
| 13 | 6 | 8 |
| 8 | 6 | 7 |
| 1 | 5 | 6 |
| 3 | 6 | 5 |
| 4 | 7 | 4 |
| 2 | 5 | 3 |
| 14 | 8 | 0 |