mysql db normalization help required - php

please forgive me as Ive been confused and I need your help in normalization of this next mysql database (will work on it along with php). If this is not allowed to post it then ignore :)
I've a need to record large number students to visit a library in order to document it and create analysis and reports later on.
These visits will hold lots of data and criteria for each student single visit, and it will be filled by different supervisor people because the student will visit more than one section.
Hence, there will be some limitations for entry and disallowing certain parts of the form to be accessed by certain users...etc.
My plan is to have a single form with some initial student information and select boxes, radio, checkboxes, and notes as free text, for each visit, as i mentioned, using php as frontend
This is what i have in mind, 2 main tables + other smaller tables to hold the select boxes data as foreign keys.
TABLE1: STUDENTS
student_id
student_number
student_name
student_gender
student_grade
student dateofbirth
student age
TABLE2: VISITS
studnet_id (referring and pulling student info from TABLE1)
date_of_visit
have_did_this_during_the_visit (DropDown)
psychological_reaction (checkboxes)
5 was_wearing_well (yes not selectbox)
And so on, more than 50 criteria to measure for each visit
This way, will have finally 2 forms, one to add student, and one to deal with visits...
Although, visits form/page will be big.. and here comes my question, is this ok? these data of visits table can exceed 40 or 50 fields or do you guys advise different approach?
Thanks for your help in advanced

Have_did_this_during_the_visit (DropDown).
for this you need one table this table will have pk anf fk on visits table's primary key
psychological_reaction (checkboxes) 5 was_wearing_well (yes not selectbox)
for this you need one table this table will have pk anf fk on visits table's primary key
TABLE2: VISITS
visit_id
studnet_id (referring and pulling student info from TABLE1)
date_of_visit
have_did_this_during_the_visit (DropDown)
psychological_reaction (checkboxes) 5 was_wearing_well (yes not selectbox)
have_did_this_during_the_visit
id
visit_id
you DropDown vaues
psychological_reaction
id
visit_id
you checkboxes vaues

Related

Mysql summary from colums

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.

Voting system using PHP+MySql?

We have to make a ballot system that makes users vote for various candidates on different positions. There's a login for voters. How do you store a vote of one voter and then get that vote added to the previous votes? The only possible way is to store every vote on a database right? But what would the structure of the database look like? And how do you count it?
edit:
The voting system doesnt only have one group of candidates to vote. It has mayor, vice-mayor, senator, etc. There are too many. that's why I'm confused. If only it was just a voting system of a president, it would be easier. So if I have a table for the voter, with a column of his/her voted candidate, it's not possible since the voter votes for many candidates.
A better way would be to have a different table to store Votes. And that table will have two attributes (VoterId, CandidateId)
And you can fetch the Vote Count if you are allowing multiple votes from this table..
But it would be better to make VoterId a Primary key in this table.. To avoid multiple voting
CandidateType: - (TypeId(PK), typeName, maxVotePerVoterForThisType)
Voter Table: - (voterId(PK), voterName, otherInfo)
Candidate Table: - (candidateId(PK), candidateName, constituency,
otherInfo, TypeId(FK))
Votes:- (voterId(PK, FK), TypeId(PK, FK), candidateId(FK))
*EDIT:- Schema edited with changed requirement in original post
*EDIT: - Added a field in CandidateType table to allow multiple votes.(E.g.: Now a voter can vote for 10 Senators, if maxVotePerVoter for this type is set to 10..)
You should e store each candidate in a table, positions in another table then make relations based on ID, the voting system is relatively simple:
database:
id, position_id, candidate_id, votes
then PHP
$query = "UPDATE `votes` SET `votes`=`votes`+1 WHERE `position_id`=1 AND candidate_id=1"; // adds 1 vote where position_id is 1 and candidate_id is 1
These 3 tables are required for your accounts (the voters) and candidates.
Account: Id (PK), Name, Password
Candidates: Id (PK), Name
Votes: AccountId (PK), CandidateId (PK)
Insert a row into votes when a vote is cast. This prevents duplicate voting due to the PK's.
I simple language i can say you are storing voting users in a table called users and you can use a field vaotecount (int) type initilize with zero and track their ip and vote for topic id on which they have voted for and when they vote you can check with IP and topic_id that they are not voting twice and if they passed you can increment the vaotecount field by one
and while you are counting for votes count the users with topic id for which you counting votes. Simple :D
From the explanation of problem, I can suggest you the following database structure:
tlbUserVote:
UserID(PK) | UserName | Vote | CandidateId(FK)
tlbCandidate:
CandidateId(PK) | CandidateName | TotalVotes
By this structure you can add the current votes with previous ones (by taking previous votes first and adding it to the current).
Total votes of the candidates will get updated, too.

Best method for storing quiz results in MySQL

I'm trying to record test/quiz scores in a database. What's the best method to do this when there might be a lot of tests and users?
These are some options I considered: should I create a new column for each quiz and row for users, or does this have its limitations? Might this be slow? Should i create a new row for each user & quiz? Should I stick to my original 'user' database and encode it in text?
Elaborating a little on the plan: JavaScript Quiz, submits score with AJAX, and a script sends it to the database. I'm new with php so i'm not sure about a good approach.
Any help would be greatly appreciated :) this is for a school science fair
I'd suggest 3 data tables in your database: students, tests, and scores.
Each student needs to have fields for an ID and whatever else (name, dob, etc) you want to record about them.
Tests should have fields for an ID and whatever else (name, date, weight, etc).
Scores should have the student ID, a test ID, and the score (any anything else).
This means you can query a student and join with the scores table to get all the student's scores. You can also join the test table these results to get labels put onto each score and calculate a grade based on scores and weight.
Alternately you can query for a test and join with the scores to get all the scores on a given test to get the class stats.
I would say create a database table, maybe one that lists all students(name, dob, student id), and then one for all tests(score, date, written by). Will only you access the db, or can your students access it too? If the latter is the case, you need to make sure the create accurate security or "views" to ensure the student can only see their own grades at a time (not everyone's).
Definitely do not create dynamic columns! (no column for each quiz). Also adding columns to user table (or generally any table) when they are not identifying the user(or generally any table item) is bad aproach...
This is pretty example of normalization, you should avoid storing any redundant rows. To do that you would create 3 tables and foreign keys to ensure scores are always referencing an existing user and quiz. E.g.:
users - id, nickname, name
quizzes - id, quizName, quizOtherData
scores - id, user_id (references users.id) , quiz_id , (ref. quizzes.id), score
And then add rows to scores table per user per quiz. Additionaly you could create UNIQUE key for columns user_id and quiz_id to disallow users to complete one quiz more times than one.
This will be fast and will not store redundant (unneeded extra) data.
To get results of quiz with id e.g. 4 and user info of people who's submitted this quiz, ordered from highest to lowest score, you would do query like:
SELECT users.*, scores.score
FROM scores RIGHT JOIN users ON(users.id=scores.user_id)
WHERE scores.quiz_id = 4
ORDER BY score DESC
Reason why I used RIGHT join here is because there might be users that didn't do this quiz, however every score always have an existing user&quiz (due to foreign keys
To get overall info of all users, quizes and scores you would do something like:
SELECT *
FROM quizzes
LEFT JOIN scores ON(quizzes.id=scores.quiz_id)
LEFT JOIN users ON(users.id=scores.user_id)
ORDER BY quizzes.id DESC, scores.score DESC, users.name ASC
BTW: If you are new to PHP (or anybody reading this), use PHP's PDO interface to communicate with your database :) AVOID functions like mysql_query, at least use mysqli_query, but for portability I would recommend stay with PDO.

PHP script for adding friends

Well I'm trying for last 5 days to create simple register, confirm, login PHP script, which is for assignment at UNI, but thing which I'm trying for last 5 days and it's not working is adding friends into friend list. Kid a like Facebook but much much simpler, it's for Android game we got as group assignment.
I have one TABLE users where I have fields ID, username, password, email, friends.
Into field friends I would like to save multiple values as ID's of your friends. To retrieve in game some of user information.
This db and tables are on MySQL and INSERT or UPDATE are not working for me, INSERT is creating new record and can't insert only to one column of existing record and UPDATE can't just insert value but will delete old one and insert new one in.
Seeing as this is a many-to-many relation (if I'm correct) so it'd be smart to create a seperate table that records this.
Table: Friends
userID
userID2 (or friendID)
Which you can fill.
For more info: http://www.singingeels.com/Articles/Understanding_SQL_Many_to_Many_Relationships.aspx
Normally you would add a freinds table with the fields:
user_id
friend_id
where both fields are references to the user tables id field.
If you - for some reason - need it to be a field in user table serialize the id values and save them there.
ATTENTION: you won't be able to easily join the tables and there is no automated possibility to keep integrity. If a user is deleted none of the references to this user in friends field will be deleted. This would all be possibile with the secondary friends table and foreign keys.
What you've described here is a many-to-many relationship between people and their friends. The canonical way do implement this in a relational database is to use a pivot table in which each row represents a "friendship" between two people. You'd have two fields to hold the IDs:
users table:
id, name, email, etc.
friendships table:
user_id_1, user_id_2
Then if user 1 is friends with user 2 and user 3, you'd have records (1,2) and (1,3) in the friendships table. You can treat these as reciprocal relationships if you like, or you can require a (2,1) record to denote that user 2 is also friends with user 1.

Multi-class, interlinked school timetable as a MySQL database

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.)

Categories