I'm looking for for an opinion.
I have a list of people and will need to store when they are present at a location so those in charge can check them off a list. I'm not 100% sure how long the dates will be needed but I'm assuming they may need to look at previous attendance lists.
My first instinct is to have a column for each date but that could result in many many columns. I could just store a list of dates next to each person:
"01/01/2012,01/15/2012,02/18/2012..."
that could result in a very long entry. It seems like neither is a good option.
If anyone has a suggestion or guidance on an approach please let me know. Thanks.
A complex, but also very clean approach would be
Table "persons":
id
name
Table "dates":
id
location
date
... whatever info the "dates" table needs
Table "attendances":
date_id (link to an entry in the "dates" table)
person_id (link to an entry in the "persons" table)
attended (yes/no)
Then fill the database with the appropriate dates, and fill the "attendances" table according to which persons need to be present at each date.
This is, as said, complex to implement, but it's incredibly flexible - you can have any number of dates and attendees; you can excuse people from attending a specific date programmatically; you can add people to groups...
Link tables.
One table of people
ID
Name
One table of classes
ID
Name
One table linking person to class to date.
ID
personID
classID
cDate
So all you would need to do to determine which students were preset on a certain date in a certain class:
SELECT *
FROM people p
LEFT JOIN peopletoclass ptc ON p.id = ptc.personid
LEFT join class c ON c.id = ptc.classid
WHERE ptc.cDate = '2011-11-07' AND c.id = '1';
Above (for example) would get all people in class id 1 on November 7th 2011.
Create a table "attendance" consisting of a person_id field and a date_present field. You can't store this into columns or a long list using a string ;-).
Than you can use queries where you join the table Person with Attendance.
Your first instinct would result in a horrible table design. What you should have is a seperate table that stores the users/locations/dates tuples
e.g.
userID locationID date
1 party 1/1/2011 00:00:00
1 bathroom 1/1/2011 00:05:00
1 party 1/1/2011 00:15:00
would show that user #1 was at a New Year's Eve party, then went to pray before the porcelain altar at 12:05am, then returned to the party 10 minutes later.
Related
I need to summary columns together on each row, like a leaderboard. How it looks:
Name | country | track 1 | track 2 | track 3 | Total
John ENG 32 56 24
Peter POL 45 43 35
Two issues here, I could use the
update 'table' set Total = track 1 + track 2 + track 3
BUT it's not always 3 tracks, anywhere from 3 to 20.
Secound if I don't SUM it in mysql I can not sort it when I present data in HTML/php.
Or is there some other smart way to build leaderboards?
You need to redesign your table to have colums for name, country, track number and data Then instead if having a wide table with just 3 track numbers you have a tall, thin table with each row being the data for a given name, country and track.
Then you can summarise using something like
SELECT
country,
name,
sum(data) as total
FROM trackdata
GROUP BY
name,
country
ORDER BY
sum(data) desc
Take a look here where I have made a SQL fiddle showing this working the way you want it
Depending upon your expected data however you might really be better having a separate table for Country, where each country name only appears once (and also for name maybe). For example, if John is always associated with ENG then you have a repeating group and its better to remove that association from the table above which is really about scores on a track not who is in what country and put that into its own table which is then joined to the track data.
A full solution might have the following tables
**Athlete**
athlete_id
athlete_name
(other data about athletes)
**Country**
country_id
country_name
(other data about countries)
**Track**
Track_id
Track_number
(other data about tracks)
**country_athlete** (this joining table allows for the one to many of one country having many athletes
country_athlete_id
country_id
athlete_id
**Times**
country_athlete_id <--- this identifies a given combination of athlete and country
track_id <--- this identifies the track
data <--- this is where you store the actual time
It can get more complex depending on your data, eg can the same track number appear in different countries? if so then you need another joining table to join one track number to many countries.
Alternatively, even with the poor design of my SQL fiddle example, it might be good to make name,country and track a primary key so that you can only ever have one 'data' value for a given combination of name, country and track. However, this decision, and that of normalising your table into multiple joined tables would be based upon the data you expect to get.
But either way as soon as you say 'I don't know how many tracks there will be' then you should start thinking 'each track's data appears in one ROW and not one COLUMN'.
Like others mentioned, you need to redesign your database. You need an One-To-Many relationship between your Leaderboard table and a new Tracks table. This means that one User can have many Tracks, with each track being represented by a record in the Tracks table.
These two databases should be connected by a foreign key, in this case it could be a user_id field.
The total field in the leaderboard table could be updated every time a new track is inserted or updated, or you could have a query similar to the one you wanted. Here is how such a query could look like:
UPDATE leaderboard SET total = (
SELECT SUM(track) FROM tracks WHERE user_id = leaderboard.user_id
)
I recommend you read about database relationships, here is a link:
https://code.tutsplus.com/articles/sql-for-beginners-part-3-database-relationships--net-8561
I still get a lot of issues with this... I don't think that the issue is the database though, I think it's more they way I pressent the date on the web.
I'm able to get all the data etc. The only thing is my is not filling up the right way.
What I do now is like: "SELECT * FROM `times` NATURAL JOIN `players`
Then <?php foreach... ?>
<tr>
<td> <?php echo $row[playerID];?> </td>
<td> <?php echo $row[Time];?> </td>
....
The thing is it's hard to get sorting, order and SUM all in ones with this static table solution.
I searched around for leaderboards and I really don't understand how they build theres with active order etc. like. https://www.pgatour.com/leaderboard.html
How do they build leaderboards like that? With sorting and everything.
I am trying to figure out how to do this SQL query, but I'm at a loss. I think I am getting in over my head.
I have three tables:
1. datetable, which contains lists of month/year up to year 2020. column is 'thedate'
2. A table containing a list of lectures. A date() field is one column, named "month"
3. A log table, which contains individual rows of data on a month to month basis. i.e Each user has their own row of data for each month of the year.
I would like to take table #2, find if there is a lecture assigned for month x, then take table #3, find the row which corresponds to month x and particular user, then see if column 'hopkins' (a part of table 3) is null or not. I hope this makes a little bit of sense. I've figured out how to use the datetable to find missing rows in table #2, but I haven't figured out how to do this above.
Thanks!
I think you just want a left join from eval to hopkins and then a test on the field:
select e.uid,
max(case when h.name is null then 0 else 1 end) as isInHopkins
from eval e left outer join
hopkins h
on year(e.month) = year(h.month) and
month(e.month) = month(h.month)
group by e.uid;
If the hopkins.id is supposed to related to the user, then you would want to add and e.uid = h.id to the on clause.
If this doesn't give you what you want, then please edit your question to provide sample results for the SQL Fiddle data.
I currently have two tables in which stores the attendances of a student in a course. I have the hub_attendance table which stores the total attendances of a student and the hub_attendance_lesson where it stores the attendance of each lesson that a student has or has not attended. I'm not sure if this is correct or if I'm doing anything wrong, I'm a beginner in databases!
hub_attendance:
id
student_id
course_id
total_lessons
total_lessons_so_far
total_attended
total_absent
total_excused_absent
total_late
total_excused_late
hub_attendance_lesson:
id
lesson_id
course_id
student_id
date
attended
absent
excused_absent
late
excused_late
EDIT:
So I've gotten rid of the first table completely and this is my new single table.
Hub_Attendance:
id
lesson_id
course_id
student_id
date
attendance
As Dutchie432 said, you don't need the first table because it introduces unnecessary redundancy and you can count those statistics on the fly. Such aggregate tables can be a good solution if performance is an issue, but they should be used only as a last resort.
About the second table - you have separate fields attended, absent, excused_absent,
late and excused_late. Aren't these mutually exclusive? So only one of them can be true for one row? If so, you may be better off with one enumeration field called for example attendance, which would take different values for each of those states. In that way you could't have rows where none of the flags, or more than one flag, is set.
Here's what you need:
**Course**
id, name, etc...
**Lesson**
id, courseid, name, etc...
**Attendance**
id, studentid, lessonid, lateness, etc...
**Enrolment**
id, courseid, studentid, startdate, etc...
You need the enrolment table to know that students should be on a course even if they never turn up for lessons. The attendance table will allow you to have many students per lesson and many lessons per student. This is a many-to-many table. Any aggregation and counting can be done in SQL.
If I understand your schema correctly, Your first table can be totally eliminated. You should be able to fetch the totals using MySQL.
select count(id) as total_late from hub_attendance_lesson where late=true and student_id=TheUserId
Remove this first table, every total can be fetch using SQL :
SELECT count(id) AS absent
FROM hub_attendance_lesson
WHERE lesson_id = <your lesson id>
AND absent = <false / true>
I guess you'll be able to adapt this code for your needs.
I've looked around for a bit now at other suggestions relating to this, but nothing I've seen has quite suited my needs, so here goes!
What I have is a multi-class (Australian secondary school; Years 7-12), multi-day (Mon-Fri) school timetable. What I now want to build is a MySQL database with the following information to be deployed on an account driven website.
Subjects:
Running time (as "Period 1 on Wednesday", "Period 2 on Friday", etc. -- multiple values in this column) Instructor (linked to separate database of all teachers) -- This would additionally need to change (temporarily) if a teacher was sick and replaced; perhaps a "replacementinstructor" column to be ignorned when NULL. Location (different, but specifically allocated, rooms on different days) -- As above, change temporarily when room altered.Other obviousnesses: Course name ("Year 7 Health"), Unique ID (Something like "7.HEALTH", rather than just auto-incrementing INT.), etc.
Teachers:
First name, last name Courses they take Contact infoOther obviousnesses: Unique ID (Auto-incrementing INT), Username (fname.lname), Password for their account, etc.
Students:
First name, last name Courses they attend (stored as an individual list for each student) Year level / Form (Year 7, Year 11, etc.)Basic personal info (Home suburb, email, etc.)More obviousnesses: Unique ID (same setup as teachers), Username (same as teachers), password, etc.
Any insight as to how I might design such a data structure would be greatly appreciated, I'm more of a UI fanatic than a MySQL thinker ;-D
Thanks in advance.
I can think of the following tables to use in MySQL:
students
Student information
id (auto_increment)
firstname
lastname
username
password
student_id (I had a student ID but I can't remember if I was given this in yr 7 or yr 10)
year
email
contact_phone
street
suburb
state (ENUM - ACT,NSW,WA,SA,TAS,VIC,NT,QLD)
teachers
Teacher information
id (auto_increment)
firstname
lastname
title (Dr, Mrs, etc)
username
password
email
contact_phone
street
suburb
state (ENUM - ACT,NSW,WA,SA,TAS,VIC,NT,QLD)
subjects
All the different subjects
id (auto_increment)
subject
subject_code (eg 7.HEALTH)
year
locations
Various locations around the school
id (auto_increment)
location (eg BLOCK A, ROOM 2, MUSIC ROOM)
subject_teachers
What subjects each teacher teaches
id (auto_increment)
subject_id
teacher_id
subject_students
Which subjects each student takes
id (auto_increment)
subject_id
student_id
subject_timetable
Main Timetable
id (auto_increment)
subject_id
location_id
teacher_id
alt_teacher_id (eg substitute teacher)
duration
period (number 1-however many periods in a day. 6 if I remember correctly)
week (number 1-2 or even perhaps 1-52)
weekday (number 1-5)
notes (as #Oswald suggested you could add additional notes for when things change)
The notes could be collated and then displayed as footnotes on the timetable.
You will obviously need a table for Subjects, a table for Students and a table for Teachers.
Read up on database normalization. This will tell you (amongst other things):
Do not put the running time into the Subject table as a comma separated list. Instead use a table for the running time and use a foreign key to map entries from that table to Subjects table.
Same goes for mapping teacher to courses.
Same goes for mapping students to courses.
That Running Time table would also be suitable for holding the location of a course during a specific running time.
Additionally, if you record temporary changes in the database, you are dependent on people changing the relevant information at a specific time. To get around this, you might want to consider a table Lessons, where you record
Running time
Week number
Course
Instructor
Location
Other fields that might be specific to that particular lesson.
This will allow you to schedule changes in advance (Mr. McCachney is sick for the next two weeks, Room 101 is closed for redecoration for a month, etc.)
I need to create a table to store users' class schedules. These schedules have 7 blocks a day for Monday through Friday. However, not all blocks are filled with classes.
I was planning on creating a table that stored stored a user's id, the period id, the class name, and the class subject in each record. If I implement it this way, what is the best way to determine when a user does not have classes using PHP? Is there a better layout for this?
You need to make three tables, and set up a many-to-many relationship.
But if you don't want to get real complex, why not just insert the students free time like a class, call it 'free time', then you can just search for those.
SELECT * FROM records WHERE student_id = '0001' AND class = 'free time'
Otherwise, I'm not sure how you'd find an empty block without having a table devoted to the blocks.
i wouldnt say you NEED to do anything, but i think you'll eventually find normalizing is a very good idea here. http://en.wikipedia.org/wiki/Database_normalization
you probably want tables for:
student (id, name, whatever)
course (id, name, subject/dept)
section (id, course id and time info)
student_to_section (student id, section id)
Time depends. You can put start/end times on sections (SQL timestamps or integer unix time stamps would each be fine) or keep a table of time slots with unique id (then sections would just have a foreign key to this id). EDIT: sounds like you've chosen the second way
As for your free-time, find the time periods for all sections taken by a student and free time is whats left. The following will give the time blocks where a student is BUSY.
SELECT T.*
FROM section S
INNER JOIN time_blocks T on S.time_id = T.id
INNER JOIN student_to_section STS on STS.section_id = S.id
WHERE STS.student_id = ###
For free time, use:
SELECT T2.*
FROM time_blocks T2
WHERE T2.id NOT IN
(put above statement here)