I have a very simple question but i can't find a good solution.
Table A:
ID_A DateStart DateEnd no_days
1 2019-02-01 2019-02-04 3
2 2019-02-04 2019-02-06 2
Table B:
ID_B ID_A Date DaysToDate
1 1 2019-02-01 10
2 1 2019-02-02 9
3 1 2019-02-03 8
4 2 2019-02-04 7
5 2 2019-02-05 6
So i'm starting with Table A and after having created one record, i create N rows for Table B.
In my project i'll then need to do the join
select * from TableA join TableB using(ID_A)
in order to have all the days listed, with their own "days to this date" value. I need the join because my user could be searching for a range of days and i need to know how many rows of TableB are involved in this search.
This is all good, it works really fast but the database is growing A LOT and i'm sure there has to be a more intelligent way to solve this problem, maybe with a static "Days" table simply listing one row per day in for the next 100 years...but i can't find a working solution because i need to keep speed and the "days to date" value.
The results i need are of this kind
select * from TableA join TableB using(ID_A) where DateStart between '2019-02-01' and '2019-02-05'
ID_A DateStart DateEnd no_days ID_B Date DaysToDate
1 2019-02-01 2019-02-04 3 1 1 2019-02-01 10
1 2019-02-01 2019-02-04 3 2 1 2019-02-02 9
1 2019-02-01 2019-02-04 3 3 1 2019-02-03 8
2 2019-02-04 2019-02-06 2 4 2 2019-02-04 7
Do you have any hints?
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'm facing an issue while creating a sql query where I want transaction details which is older than 2 months. Can someone help me with this.
Basically, I have two table one transaction tables and one customer table.
For each customer there is record of transactions in transaction table. So, now I want a query which can retrieve all the customer_ids which didn't have any transactions in past 2 months.
Customers
id
name
1
Google
2
Facebook
3
Hooli
4
Yahoo!
Transaction
id
transaction_date
customer_id
1
2022-04-10
1
2
2022-04-05
1
3
2022-03-09
1
4
2022-03-24
1
5
2022-02-23
2
6
2022-02-22
2
7
2022-02-21
2
8
2022-03-24
2
9
2022-03-24
3
10
2022-01-23
4
11
2022-01-22
4
12
2022-01-21
4
Output
Customer_id=4(since it do not have any transactions in past 2 months)
Thank you
You can use the MySQL INTERVAL in your select query. Like this:
SELECT customer_id FROM `transaction`
GROUP BY customer_id
HAVING (CURDATE() - INTERVAL 2 MONTH) > MAX(transaction_date);
OUTPUT
customer_id
-------------
4
This query is based on the MAX(transaction_date) of the customer.
I have two tables:
Table 1: planA
ID Date Count
3 2017-01-01 10
2 2017-02-03 15
10 2017-01-30 8
Table 2: planB
ID Date Value
3 2017-01-02 11
2 2017-02-04 12
21 2017-01-30 3
3 2017-02-03 33
What I want to do is to join the two tables on (ID and Date) columns.
However, on Date, I want to use the next day to the date on the table 1.
Therefore, the joined table should look like the following:
PlanA.ID PlanA.Date PlanB.Date PlanA.Count PlanB.Value
3 2017-01-01 2017-01-02 10 11
2 2017-02-03 2017-02-04 15 12
Is this even possible?
Any suggestion would be appreciated!
Yes it is possible:
select
PlanA.ID,
PlanA.Date,
PlanB.Date,
PlanA.Count,
PlanB.Value
from
PlanA inner join PlanB
on (
PlanA.ID = PlanB.ID
and
PlanA.Date + INTERVAL 1 DAY = PlanB.Date
)
if Date is a column of type date, + INTERVAL 1 DAY will return the next day of the one given, and then you can perform the join.
It is an additional question to my previous one that is already answered.
There are 4 tables: buildings, rooms, reservations, information
1 building = n rooms
1 room = n reservations
TABLE BUILDINGS - ID(int), name(varchar)
TABLE ROOMS - ID(int), building_id(int)
TABLE RESERVATIONS - ID(int), room_id(int), date_start(datetime), date_end(datetime)
TABLE INFORMATION - ID(int), building_id(int), hours_start(int), hours_end(int)
Buildings table example
ID name
1 Building A
2 Building B
3 Building C
Rooms table example
ID building_id
1 1
2 1
3 2
4 3
Reservations table example
ID room_id date_start date_end
1 1 2014-08-09 14:00:00 2014-08-09 14:30:00
2 1 2014-08-09 14:30:00 2014-08-09 15:30:00
3 3 2014-08-09 16:30:00 2014-08-09 17:30:00
4 2 2014-08-09 16:00:00 2014-08-09 17:00:00
5 3 2014-08-09 16:00:00 2014-08-09 16:30:00
Information table example
ID building_id hours_start hours_end
1 1 9 22
2 2 8 20
3 3 8 22
Question
Can we filter buildings that has atleast 1 available room on selected date in any hour? Buildings working hours may be different (Information table).
I think this will do what you want. It calculates the total number of meeting hours in the building for all the rooms. It then calculates the total meeting hours. If a room is available the second is less than the first:
SELECT b.id, b.name,
sum(timestampdiff(minute, rv.date_start, rv.date_end))/60 as MeetingHours,
max(hours_end - hours_start)*count(distinct r.id) as BuildingHours
FROM buildings b JOIN
information bi
on b.id = bi.building_id
rooms r
ON b.id = r.building_id LEFT JOIN
reservations rv
ON rv.room_id = r.id AND
'2014-08-09' between date(rv.date_start) AND date(rv.date_end)
GROUP BY b.id
HAVING MeetingHours is Null or MeetingHours < BuildingHours;
I have the following table:
id | start_date | end_date | client_id
1 2013-08-01 2013-08-09 1
2 2013-08-10 2013-08-10 1
3 2013-08-10 2013-08-17 1
4 2013-08-18 2013-08-18 1
5 2013-08-18 2013-08-18 1
6 2013-08-18 2013-08-31 1
7 2013-08-01 2013-08-09 2
8 2013-08-11 2013-08-11 2
9 2013-08-11 2013-08-17 2
10 2013-08-19 2013-08-20 2
what I'm trying to do is count the number of days that each client was present without repeating the days for each client, so from the previous data I'm looking to get:
client_id | total_days
1 31
2 18
So for client 1 I get 31 because he was "present" for 31 days, from 8/1/2013 - 8/31/2013 with no gaps, and for client 2 I get 18 because he was present for 18 days:
8/1 - 8/9 = 9 days
8/11 - 8/17 = 7 days
8/19 - 8/20 = 2 days
is there anyway to achieve this in MySQL, I've been trying for a while but have no idea on how to do it.
This is the fiddle
If overlapping ranges exist, then I suggest building a driver table that is a list of dates, then JOIN to that table using BETWEEN:
SELECT a.Client_ID, COUNT(DISTINCT b.Date)
FROM YourTable a
JOIN Dates b
ON b.Date BETWEEN a.start_date AND a.end_date
GROUP BY a.Client_ID
Demo: SQL Fiddle
There are plenty of places to find calendar table logic, here's one.
If ranges never overlap then you can use SUM(DATEDIFF()).
If there are no overlapping ranges. You can use the following query:
SELECT Client_id,
Sum(DATEDIFF(End_date, Start_date)) AS `Present`
FROM TABLE
GROUP BY Client_id;
This will give you an overview of the number of days a client was present.