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;
Related
hi guys i really newbie in sql, i need help to generate percentage of attendance, here is the table:
Table Schedule
Schedule_ID Course_ID Lecture_ID Start_Date End_Date Course_Days
1 1 11 2019-09-09 2019-12-08 2,4,6
2 3 4 2019-09-09 2019-12-08 3,4
3 4 13 2019-09-09 2019-12-08 2,5
4 5 28 2019-09-09 2019-12-08 3
5 2 56 2020-01-27 2020-04-26 2,4
6 7 1 2020-01-27 2020-04-26 4,5
7 1 11 2020-01-27 2020-04-26 2,4,6
8 7 22 2020-01-27 2020-04-26 2,3
9 8 56 2020-01-27 2020-04-26 5
10 3 37 2020-01-27 2020-04-26 5,6
Reference of days of week used in this data.
1: Sunday, 2:Monday, 3:Tuesday, 4:Wednesday, 5:Thursday, 6:Friday, 7:Saturday
Table course_attendance
ID STUDENT_ID SCHEDULE_ID ATTEND_DT
1 1 2 2019-09-10
2 1 2 2019-09-11
3 1 2 2019-09-17
4 1 2 2019-09-18
......
46 2 1 2019-12-02
47 2 1 2019-09-11
48 2 1 2019-09-18
49 2 1 2019-09-25
50 2 1 2019-10-09
51 2 1 2019-10-16
....
111 6 1 2019-09-23
112 6 1 2019-09-30
113 6 1 2019-10-07
114 6 1 2019-10-14
table student
ID NAME
1 Jonny
2 Cecilia
3 Frank
4 Jones
5 Don
6 Harry
i need to show up like this :
STUDENT_ID NAME Course_ID Attendance rate
1 Jonny 1 82%
2 Cecilia 1 30%
3 Frank 3 100%
4 Jones 2 100%
5 Don 2 25%
6 Harry 4 40%
EDIT this my last step to get percentage:
result:
with main as (
select ca.STUDENT_ID,
ca.SCHEDULE_ID,
s.COURSE_ID,
co.NAME as course_name,
st.NAME,
count(ca.ID) as total_attendance,
((CHAR_LENGTH(s.COURSE_DAYS) - CHAR_LENGTH(REPLACE(s.COURSE_DAYS , ',', '')) + 1) * 13) as attendance_needed
from univ.course_attendance ca
left join univ.schedule s on ca.SCHEDULE_ID = s.ID
left join univ.student st on ca.SCHEDULE_ID = st.ID
left join univ.course co on ca.SCHEDULE_ID = co.ID
group by ca.STUDENT_ID, ca.SCHEDULE_ID
)
select *,total_attendance/attendance_needed as attendance_percentage
from main
order by 1,2;
This can be done following three steps.
Step 1: Calculate the total number of days a particular course of a schedule has. It's a good thing the start_date is always on Monday and the end_date is always on Sunday, which makes the week complete and saves some trouble. By calculating the total number of weeks a course go through and the number of days a week has for that course, we can get the total number of days a particular course of a schedule has.
Step 2:Calculate the total number of days a student for a schedule. This is done fairly easily. Note: As the majority part of the table has been skipped and the OP has yet to provide the complete data set, I could only have 14 existing rows provided.
Step 3: Calculate the percentage for the attendance using the result from the above two steps and get other required columns.
Here is the complete statement I wrote and tested in workbench:
select t2.student_id as student_id,`name`,course_id, (t2.total_attendance/t1.total_course_days)*100 as attendance_rate
from (select schedule_id,course_id,
length(replace(course_days,',',''))*(week(end_date)-week(start_date)) as total_course_days
from Schedule) t1
JOIN
(select count(attend_dt) as total_attendance,student_id,schedule_id
from course_attendance group by student_id, schedule_id) t2
ON t1.schedule_id=t2.schedule_id
JOIN
student s
ON t2.student_id=s.id;
Here is the result set ( the attendance_rate is not nice due to the abridged course_attendance table):
student_id, name, course_id, attendance_rate
2, Cecilia, 1, 15.3846
6, Harry, 1, 10.2564
1, Jonny, 3, 15.3846
I have the following table:
id post_id user_id to_user_id date time
---- ---------- -------- ------------ ------
1 100 1 2 10:00
2 100 1 2 10:30
3 100 2 2 11:00
4 100 5 2 11:30
5 100 8 2 11:45
6 105 10 50 09:00
7 105 2 50 09:30
8 105 11 50 11:00
9 105 30 50 11:30
10 105 32 50 11:45
On the following table you can see that user_id 2 has comments for post 100 and 105.
I need to get only the records per post_id that is hight than the first comment he wrote.
so for this example the result will be records 4 and 5 for post 100 and 8, 9, 10 for post 105 because 4, 5 is bigger than 3 (first record for user_id 2)
and 8, 9, 10 is bigger than 7 (user_2 first comment)
clear expected result:
id post_id user_id to_user_id date time
4 100 5 2 11:30
5 100 8 2 11:45
8 105 11 50 11:00
9 105 30 50 11:30
10 105 32 50 11:45
Could be with a subselect and an aggregation function
select * from my_table
where ( post_id, date_time) > (select post_id, max( date_time)
from my_table where user_id =2
group y post_id);
or if the tuple version donìt work properly try
select * from my_table as m
inner join (select post_id, max( date_time)
from my_table where user_id =2
group y post_id ) t on m.post_id = t.post_id
where m.date_time > t.date_time
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.
I have a favorite table with 4 columns
employee_id
product_id
frequency
last_consumed_date
Now i'm getting the 6 rows with the highest frequency for the employee_id with a minimal frequency of 6.
Example with employee_id 1
SELECT * FROM `favorites`
WHERE `employee_id` = 1
AND `frequency` >= 6
ORDER BY `frequency` DESC LIMIT 0,6
So far so good!
But now i want to prefer the rows if the last_consumed_date is within a month (30 days), So i must do something with:
DATE_SUB(CURDATE(),INTERVAL 30 DAY) <= `lastchanged`
Here is a table example to make it more clear
Table filled:
1 5 11 2012-10- 3
1 13 8 2012-11- 7
1 18 20 2012- 9-25
1 42 10 2012-11- 3
1 28 15 2012-10-17
1 9 7 2012-10- 8
1 64 9 2012-11- 1
2 24 8 2012- 8-28
2 12 5 2012-10-16
2 5 12 2012-11-11
Today is 2012-11- 8
30 days back is 2012-10- 9
Table returned after SQL:
1 28 15 2012-10-17 <Sorted by 30 days interval and frequency>
1 42 10 2012-11- 3
1 64 9 2012-11- 1
1 13 8 2012-11- 7
1 18 20 2012- 9-25 <Sorted by frequency>
1 5 11 2012-10- 3
Now the question is, How do i order those 2 things in 1 query?
First an order by the date (with 30 days interval)
and than an order by the frequency of seperated results (inside interval and all others)
Ohh i think i found my answer by trial-error ^v^
SELECT * FROM `favorites`
WHERE `employee_id` = 1
AND `frequency` >= 6
ORDER BY (DATE_SUB(CURDATE(),INTERVAL 30 DAY) <= `lastchanged`) DESC,
`frequency` DESC
LIMIT 0,6
For those who tried helping! Thank you
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;