mysql pivot query and rank Query - mysql

I Have a marksheet table like:
ID STUDENT_ID Branch_id Class_id Exam_id Subject_id Numbers Date
1 653 5 1 1 8 60 2012-01-01
2 653 5 1 1 9 40 2012-01-01
3 653 5 1 1 10 80 2012-01-01
4 653 5 1 1 11 50 2012-01-01
5 653 5 1 1 12 65 2012-01-01
6 653 5 1 1 13 33 2012-01-01
7 653 5 1 1 15 86 2012-01-01
8 222 5 1 1 8 100 2012-01-01
9 222 5 1 1 9 80 2012-01-01
10 222 5 1 1 10 92 2012-01-01
11 222 5 1 1 11 50 2012-01-01
12 222 5 1 1 12 65 2012-01-01
13 222 5 1 1 13 33 2012-01-01
7 222 5 1 1 15 86 2012-01-01
I want to get rank I got answer by this question
Also when I fetched all class result I use pivot query:
SELECT stu_id, sum(numbers) AS total, branch_id, depart_id, class_id,
SUM( IF( subject_id =1, numbers, 0 ) ) AS MAth,
SUM( IF( subject_id =2, numbers, 0 ) ) AS Eng,
SUM( IF( subject_id =3, numbers, 0 ) ) AS Science
FROM marksheet where branch_id = 1 AND depart_id = 1
AND class_id = 1 GROUP BY stu_id ORDER BY total DESC
I want to get rank in my class query (pivot query)? And I want to count how many students on first position and how many on second and third?
Required Data sample:
ID Name Math English Science Total Percent Position Rank
Any one help?

I think what you need to do is create a second table with grade boundaries that are being referenced so for instance :
ID grade start_boundry end_boundry
1 A 60 100
ect..
then create a join between the tables and then do a WHERE statement between the Numbers and the start/ end boundries
so ->
SELECT grade FROM boundries_table RIGHT JOIN sudent_table
WHERE boundries_table.start_boundry < student_table.numbers
AND boundries_table.end_boundry > student_table.numbers
i think that should work if my MySQL memory serves, just modify the table to how you need it to run and it should work for how you need it.

Related

MySQL: select sum of column having specific values

What I'm trying to do is to select a specific amount of tickets (max 2) and every person that has the sum of the number of tickets less of 3 and the valid field has to be != 'e'
I have this table:
ID
id_person
nr_tickets
valid
1
220
1
s
2
220
1
s
3
330
2
s
4
330
1
e
5
331
1
s
6
220
2
s
7
441
1
s
8
442
2
s
9
443
1
s
10
444
1
s
11
445
2
s
Here is what I did:
SELECT m.id, m.id_person, m.nr_tickets, m.valid
FROM table m
JOIN table m1 ON m1.id <= m.id
WHERE m.nr_tickets > 0
GROUP BY m.id
HAVING SUM(case when m.valid != 'e' then m1.nr_tickets end) <= 10
This query gives me
ID
id_person
nr_tickets
valid
1
220
1
s
2
220
1
s
3
330
2
s
5
331
1
s
6
220
2
s
7
441
1
s
8
442
2
s
As you can see the query it's almost right, the thing is that the person 220 in the results has the sum of the tickets is greater than 2.
What I'm trying to achieve is to bypass the ID 6, and to have instead the ID 9
select `id`,`id_person`, sum(`nr_tickets`) as `nr_tickets`, `valid`
from `test`
group by `id_person`
having sum(`nr_tickets`) < 3 and `valid`!="e"
Output:
id id_person nr_tickets valid
5 331 1 s
7 441 1 s
8 442 2 s
9 443 1 s
10 444 1 s
11 445 2 s

HIVE how to limit number of entries in group

I'm learning HIVE these days and meet some problems...
I have a table called SAMPLE:
USER_ID PRODUCT_ID NUMBER
1 3 20
1 4 30
1 2 25
1 6 50
1 5 40
2 1 10
2 3 15
2 2 40
2 5 30
2 3 35
How can I use HIVE to group table by user_id and in each group order the records by DESC order of NUMBER and in each group I want to keep up to 3 records.
The result I want to have is like:
USER_ID PRODUCT_ID NUMBER(optional column)
1 6 50
1 5 40
1 4 30
2 2 40
2 3 35
2 5 30
or
USER_ID PRODUCT_IDs
1 [6,5,4]
2 [2,3,5]
Could someone help me ?..
Thanks very much!!!!!!!!!!!!!!!!
try this,
select user_id,product_id,number
from(
select user_id,product_id,number, ROW_NUMBER() over (Partition BY user_id) as RNUM
from (
select user_id, number,product_id
from SAMPLE
order by number desc
) t) t2
where RNUM <=3
output
1 6 50
1 5 40
1 4 30
2 2 40
2 3 35
2 5 30
hive version should be 0.11 or greater, may I know if your version is lower

MYSQL group by month but not on first day of month

My table votes contains votes that have been made by users at different times:
id item_id position user_id created_at
1 2 0 1 11/21/2013 11:27
26 1 1 1 11/21/2013 11:27
27 3 2 1 11/21/2013 11:27
42 2 2 1 12/7/2013 2:20
41 3 1 1 12/7/2013 2:20
40 1 0 1 12/7/2013 2:20
67 2 2 1 12/13/2013 1:13
68 1 1 1 12/13/2013 1:13
69 3 0 1 12/13/2013 1:13
84 2 0 1 12/28/2013 2:29
83 3 2 1 12/28/2013 2:29
82 1 1 1 12/28/2013 2:29
113 3 0 1 1/17/2014 22:08
114 1 1 1 1/17/2014 22:08
115 2 2 1 1/17/2014 22:08
138 2 0 1 1/20/2014 16:49
139 1 1 1 1/20/2014 16:49
140 3 2 1 1/20/2014 16:49
141 1 1 11 1/20/2014 16:51
142 3 2 11 1/20/2014 16:51
143 2 0 11 1/20/2014 16:51
I need to tally the results on a monthly basis but here's the tricky part: the start/end of the month does not necessarily fall on the first day of the month. So if the votes are due on the 10th day of every month, I need a vote that was cast on the 10th to be in a different group from a vote that was cast on the 11th. Using the data above, I want to get three groups:
Group 1: 6 votes (11/21 and 12/7)
Group 2: 6 votes (12/13, 12/28)
Group 3: 9 votes (1/17, 1/20)
I've tried a lot of approaches but to no avail. This is my query right now:
select created_at, ADDDATE(DATE_FORMAT(created_at, '%Y-%m-01'),interval 10 day) as duedate,count("id") from votes where list_id = 2 group by duedate
I am getting group sizes of 3, 9, and 9, not 6, 6 and 9. Any help you can provide would be much appreciated. Thanks.
Your query is close. You just need to subtract 9 days (10 - 1) from the current day to get the month:
select created_at, date_sub(created_at, interval 9 day) as duedate,
count(id)
from votes
where list_id = 2
group by duedate;
date_format() converts a date to a string. There is no need to convert a date value to a character value for this query.
EDIT:
To group by month:
select date_format(date_sub(created_at, interval 9 day), '%Y-%m') as YYYYMM,
count(id)
from votes
where list_id = 2
group by YYYYMM;

Dynamic Get Rank By Mysql Query

I have a result table like:
ID STUDENT_ID Branch_id Class_id Exam_id Subject_id Numbers Date
1 653 5 1 1 8 60 2012-01-01
2 653 5 1 1 9 40 2012-01-01
3 653 5 1 1 10 80 2012-01-01
4 653 5 1 1 11 50 2012-01-01
5 653 5 1 1 12 65 2012-01-01
6 653 5 1 1 13 33 2012-01-01
7 653 5 1 1 15 86 2012-01-01
8 222 5 1 1 8 100 2012-01-01
9 222 5 1 1 9 80 2012-01-01
10 222 5 1 1 10 92 2012-01-01
11 222 5 1 1 11 50 2012-01-01
12 222 5 1 1 12 65 2012-01-01
13 222 5 1 1 13 33 2012-01-01
7 222 5 1 1 15 86 2012-01-01
My Desire Result like:
Student_ID Math English Science Total Rank
1 90 89 88 267 1
2 90 89 88 267 1
3 58 45 98 201 2
I want to get student rank by this method:
Reference Link
SET #rank = 0, #prev_val = NULL;
SELECT rank, correct FROM
(
SELECT
#rank := IF(#prev_val=correct,#rank,#rank+1) AS rank,
#prev_val := correct AS correct, uid
FROM quiz_user
ORDER BY correct DESC
)as result WHERE uid=xxxxxxxxxxxx
This query what I need only difference between table structure the author of post assign a rank on correct column and I need to assign rank on numbers SUM(numbers) column after sum all numbers.
Please Help.
Try this:
SELECT STUDENT_ID, Numbers, IF(#marks=(#marks:=Numbers), #auto, #auto:=#auto+1) rank
FROM (SELECT STUDENT_ID, SUM(Numbers) Numbers
FROM quiz_user
GROUP BY STUDENT_ID
ORDER BY Numbers DESC, STUDENT_ID
) AS A, (SELECT #auto:=0, #marks:=0) AS B;

mySQL AVG a field with a range of dates on the same table

I have a table
date d_id r_id p_id q_sold onhand
2012-10-10 5 1 3025 3 10
2012-10-10 5 1 3022 12 20
2012-10-10 5 1 3023 15 33
2012-10-11 5 1 3025 3 10
2012-10-11 5 1 3022 12 20
2012-10-11 5 1 3023 15 33
2012-10-12 5 1 3025 3 10
2012-10-12 5 1 3022 12 20
2012-10-12 5 1 3023 15 33
2012-10-13 5 1 3025 3 10
2012-10-13 5 1 3022 12 20
2012-10-13 5 1 3023 15 33
2012-10-14 5 1 3025 3 10
2012-10-14 5 1 3022 12 10
2012-10-14 5 1 3023 15 33
2012-10-15 5 1 3025 3 5
2012-10-15 5 1 3022 12 5
2012-10-15 5 1 3023 15 33
I would like to get the result of the q_sold divided by average of the onhand over a 5 day period, while displaying the other data for a specific date like the 2012-10-15.
I create a query
set #stdate = '2012-10-10';
set #endate = '2012-10-15';
SELECT date, d_id,r_id,p_id,q_sold,onhand,qty_sold/AVG(qty_onhand)
FROM stp_vwsales_info_tots
WHERE date BETWEEN #stdate and #endate and d_id=5
GROUP BY d_id,r_id,p_id
But the result being showed is incorrect, it displays the data for the 2012-10-10 instead of 2010-10-15
date d_id r_id p_id q_sold onhand avg
2012-10-10 5 1 3022 12 20 0.7579
2012-10-10 5 1 3023 15 33 0.4545
2012-10-10 5 1 3025 3 10 0.3273
Can anyone help?
Use your #stdate and #endate as DATE(#stdate/#endate) or DATE_FORMAT(#stdate/#endate,'%Y-%m-%d') otherwise you have to convert #stdate/#endate from string to date through MySQL
i think what your looking for is something called a simple moving average.
to calculate this you'll need to use an inline subquery - so performance won't be the best.
assuming you want to calculate the average over the previous 5 day period, try something like this:
SELECT
date, d_id, r_id, p_id, q_sold, onhand,
( SELECT q_sold/AVG(t2.onhand)
FROM stp_vwsales_info_tots AS t2
WHERE p_id=t1.p_id AND DATEDIFF(t1.date, t2.date) BETWEEN 0 AND 4
) AS 'moving_avg'
FROM stp_vwsales_info_tots AS t1
GROUP BY t1.p_id,t1.date
order by t1.date;