Choice of tables for handling attendance - php

I'm working on my project in PHP [handling students attendance system]. I have a list of students along with their id[jntuno] and I need to create a database in mysql for storing the daily attendance of each student for each subject.So I created my tables in this way :
TABLE : students
FIELDS:
slno int(5) auto increment,
jntuno char(15),
name char(50),
primary key(slno,jntuno).
DATA:
this students table holds the list of students and their id
now I created another table :
TABLE: dailyatt
FIELDS:
date date,
subject char(10),
classesconducted int(2),
`11341A0501` int(2),
`11341A0502` int(2),
`11341A0503` int(2),
.
.
.
`11341A0537` int(2),
primary key(date,subject).
this table will look like :
+------------+-----------+-----------------+------------+-----------+-----------+
|date |subject |classesconducted |11341A0501 |11341A0502 |11341A0503 |....
+------------+-----------+-----------------+------=-----+-----------+-----------+
| | | | | | |
now every day upon entering the attendance in the PHP website, a new row will be created for each subject taught on that day.
But many said that the database model is not a good one ...
What's wrong with this database structure?
So can someone suggest me a better model for this kind of problem?

Image you have 200 students offered at your school. You would have 200+ columns in your second table. You should split it up to two tables. One for all the classes that are offered at school and the second for the actual attendance records.
"classes" table
"attendance table"
Then join them together.
SELECT student_id, class_name, date, class_attended
FROM attendance AS ABB2
LEFT JOIN classes AS ABB1 ON ABB1.id = ABB2.class_id

You are creating a column for every student, I think is the bad thing.
Why you just not create table like this one?
`date` date,
`slno` int(5),
`slnoconducted` int(2),
`subject` char(10),
primary key(`date`, `slno`, `subject`)
So, you can insert in this table some values like:
("2013-10-06", 1, 5, "Class A")
And it will be treated as: By the date 2013-10-06 the student with slno #1 (11341A0501) gained slnoconducted == 5 with the description "Class A".
After, if you want, for example, to get all records today, you can use query:
SELECT * FROM dailyatt WHERE `date` = '2013-10-06'
If you want to get all records for one student, you can use query:
SELECT * FROM dailyatt WHERE `slno` = 1
And even:
SELECT d.*, s.`jntuno`, s.`name`
FROM `dailyatt` d
LEFT JOIN `students` s ON d.`slno` = s.`slno`
WHERE `date` = '2013-10-06'
It is better way to deal with records. If you will create column for every student, you will lose flexibility of the DB, because you will have to create/delete another column after any changes in students table.
I hope I described it correctly, because I'm not sure I have good English.

Related

Resolving table(mysql, php)

I got 3 table, called class , student and class_student(resolving table) . This is due to many to many relationship between class and student. A student can have many class and a class can have many student. The fields inside class is(class_id, class_start_time and class_end_time) , student(student_id, student_name, student_age) , class_student(student_id , class_id). My question would be : Inside a class, it includes student , how do I add student into the class table ? Or should I make use of the resolving table? My understanding of resolving table is weak and I'm not sure what's the purpose of it.
Thank you all for your answer !
What about when I add a new record to class student table , do I add a new record to class table as well?
The most common way to resolve a many to many relationship is via a seperate relation table (as Barmar noted).
In your case that table could have these fields:
table class_students
--------------------
id // an unique id of that relationship;
// could be ommitted, could be an autoincrement,
// could also be a "handcrafted" id like classid_userid -> 21_13 (I need this kind of id's for an ember-api.
// All depending on your needs
class // the id of the related class
student // the id of the related student
// maybe add additional fields:
type // to describe that relationship
sort
You then would get all the students of a specific class like so:
$class_id = 1;
$sql = "Select * from students, class_students where students.id=class_students.student AND class_student.class=".$class_id;
// note, that you should do that via prepared statements,
// this is only for simplicity to show how to proceed.
You are not going to add students in the class table. If you do so, there is no point separating class from student in the first( you have prevented redundancy of data ). I believe the table structure is good enough to achieve your objectives. The secondary keys (student_id , class_id) which are primary key in the student and the class tables respectively does the job.
class table
id| title | start | end
1 Biology 8am 10am
2 English 10am 12pm
student table
id | name |
1 John
2 Doe
student_class table
student_id | class_id
1 1
1 2
2 1
from the table, i could
Get all courses John( user.id: 1 ) registered for
SELECT FROM student_class WHERE student.student_id = '1'
All the students that registered for Biology (class.id: 1)
SELECT FROM student_class WHERE student.class_id = '1'
Note I know you will need the name of the student here in the result.
Very simply , just 'LEFT JOIN' class table with student_class table on student_class.class_id = student.id
Then for each record you get from student_class table, the 'name' (or other columns you choose to include in the result set) will be added from the class table.
Note the way you just joined the class table, you can do the same for student table. for example, You want the student to print their time table for classed they registered for, you will still select from student_class table and get the start and the end time using LEFT JOIN

MySQL multiple primary in one table and foreign key to another table

i am using myphpadmin
tabel 1
id exam_name month year
------------------------------------
1 universityexam january 2013
here exam_name, month and year is primary key
table 2
id exam_name course_name
----------------------------------------------
1 universityexam january 2013 bsc
here exam_name is foreign key to all the column of the table 1
I think I know what the problem is but please forgive if your lack of detail has resulted in misunderstanding.
What you seem to want to be able to do is to link the two tables, but you are going about it the wrong way. You should use the id from table1 as the FK in table2. What you are doing is duplicating data unnecessarily.
It is possible to link one exam to many courses or one course to many exams in this way.
I would design the database thus:
create table courses (degree_id int,degree_name varchar(128))
create table exam (exam_id int,exam_name varchar(128))
create table exam_date(exam_date_id SERIAL,exam_id int,date timestamp)
create table exam_date_course(edc_id SERIAL,exam_date_id BIGINT,degree_id INT)
This allows you to link exams to dates, courses to exams etc very freely with little or no duplication of data (see 4th normal form on google)

how can i get ORM to work with 2 separate databases without foriegn keys defined in the tables?

I'm not even sure if this is possible. I am using Kohana framework(ver 2.3). I have 2 separate databases. One called 'employees' and another called 'tracker'. The databases are used in 2 different websites. I want to eliminate a table in the tracker database called 'csr', which contains identical employee data, and link the tracker to the employee info in the employees database.
In my tracker application I have a model setup for employees which references the external 'employees' database. I can query it with ORM from the tracker application and all is well. the unique key for employees is 'id'.
In my tracker database I have a model for 'records' table with about 12k entries. None of the field names correspond to any field names in the employees table from the employees database but some fields do contain identical information. The unique key for 'records' is Transaction_Number
Please note I did not write this application or design the databases. I am trying to "retro-fit" the tracker application to use the, now centralized, employee data .
There are 9 fields in 'records' that contain matching information in the employees database. This 9 fields contain employee id's and names but are not all the same id.
I can change the data in these 9 fields so that they are all employee id's if it would help but I need to be able to get employee data: names, addresses, etc., based on the id in any of those 9 fields
Redesigning the database would cause a rewrite of the tracker application and I really don't have the time to do all that.
To save some reading, I am not including the table structures here but I can add them if needed.
What can I do to link these two tables together?
EDIT: Added table structure for tracker.records
TRACKER.RECORDS
Transaction_Number (PK AI not null)
date
accountnumber
reasoncode
reasondesc
actioncode
actiondesc
comments
supervisor - employee->id (supervisor that created the record)
supername - employee->name
supersuper - employee->parent->name
superman - employee->parent->parent->name
eid - employee->id (employee that the record is about)
Service_Rep - employee->name
ServRepSupervisor - employee->parent->name
ServRepManager - employee->parent->parent->name
csrfollow - employee->name (who to follow up with)
Important
Read
Followup_Read
followup_Important
the employee table is using ORM_Tree to be self relational.
I need to be able to get employee info for any of those fields. I can change the data in each of those fields to be an employee id and i think i can eliminate some of them. the only ones I rally need are supervisor(employee->id), eid(employee->id) and csrfollow(can be changed to employee->id). the other fields can be discovered based on the employee->id. I still need to have those 3 fields point to the employee.id field in the employees database.
Are you aware that MySQL allows foreign keys to reference tables across databases, as long as both databases are hosted on the same instance of MySQL?
CREATE TABLE `employees` (
`id` bigint(20) unsigned NOT NULL AUTO_INCREMENT PRIMARY KEY
-- other columns...
) ENGINE=InnoDB DEFAULT CHARSET=latin1;
CREATE TABLE `records` (
`id` bigint(20) unsigned NOT NULL AUTO_INCREMENT PRIMARY KEY,
`employee_id` bigint(20) unsigned DEFAULT NULL,
-- other columns...
FOREIGN KEY (`employee_id`) REFERENCES `employees`.`employees` (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=latin1;
You just have to qualify the referenced table name with its database name.
Re your update: You can change the name of RECORDS to RECORDS_BASE with the distinct data that belongs in TRACKER.
TRACKER.RECORDS_BASE
Transaction_Number (PK AI not null)
date
accountnumber
reasoncode
reasondesc
actioncode
actiondesc
comments
supervisor_id
eid
Important
Read
Followup_Read
followup_Important
Then create a new VIEW called RECORDS that joins RECORDS_BASE to multiple rows in EMPLOYEES:
CREATE VIEW TRACKER.RECORDS AS
SELECT rb.*,
s.id AS supervisor,
s.name AS supername,
ss.name AS supersuper,
sss.name AS superman,
emp.name AS Service_Rep,
srs.name AS ServRepSupervisor,
srm.name AS ServRepManager,
??? AS csrfollow
FROM TRACKER.RECORDS_BASE AS rb
JOIN EMPLOYEES.EMPLOYEES AS s ON rb.supervisor_id = s.id
JOIN EMPLOYEES.EMPLOYEES AS ss ON s.parent_id = ss.id
JOIN EMPLOYEES.EMPLOYEES AS sss ON ss.parent_id = sss.id
JOIN EMPLOYEES.EMPLOYEES AS emp ON rb.eid = emp.id
JOIN EMPLOYEES.EMPLOYEES AS srs ON emp.parent_id = srs.id
JOIN EMPLOYEES.EMPLOYEES AS srm ON srs.parent_id = srm.id;
I can't tell from your description what belongs in the csrfollow column. Whose name is it? Anyway I'll leave that for you to decide. I've shown how you can get a reference to each of the relevant rows in the employees table, so take your pick.

Need advice to change my database design

I need to change the way I am storing information in the DB. Because the query works slow with the old model I had developed.
General problem is following.
1) I have list of courses, and each course has list of tags describing general content of the course. For instance, the course called "Database Management Systems" could have following tags {sql, index, key, relation}.
2) I have professors who have tags also which generally describe what do they teach in their courses . For example, Barton {sql, php, apache,mysql}
I need to find all professors in the DB who match best to the specific selected course. Also I need to sort them by their weight of matching.
Question
The question is how to store this information in the DB and how to process this stored information in order to solve this problem.
This question appeared after I received a lot of negative critiques about my sql query here.
Well, I would start with something like these 5 tables:
Course (CourseID, CourseName, ...)
Professor (ProfID, ProfName, ...)
Tag (TagID, TagName)
CourseTag (CourseID, TagID)
ProfTag (ProfID, TagID)
and query it something like
SELECT ProfName, Count(PT.TagID) AS Weighting
FROM Professor P
INNER JOIN ProfTag PT ON P.ProfID = PT.ProfID
INNER JOIN CourseTag CT ON PT.TagID = CT.TagID
WHERE CT.CourseID = #SelectedCourse
GROUP BY ProfName
That's MS SQL Server syntax...don't know what you're using (but with php, probably not that :))
Sounds like you should have the following tables:
Course - lists the courses.
Subject_area - a list of subjects that courses can cover, like "sql", "c++" etc.
Course_content - cross reference table between Course and Subject_area.
Professor - lists the professors.
Professor_expertise - cross reference table between Professor and Subject_area.
For example, you might have a Professor called "Prof. Brown" with a corresponding row in table Professor, and also subject areas called "sql", "java" and "optimisation algorithms" each of which Prof. Brown is interested in. Then there would be a corresponding row for each of those areas in Professor_expertise, and each one would reference Prof. Brown's row in table Professor, and also the appropriate row in table Subject_area.
Now suppose you have a course "SQL and Database Design", and it has subject areas "Database Design", "SQL", "Database Indexes", "Normalisation" and "Query optimisation". You could see which professors are suited to teach the course by issuing
SELECT
Professor.Name,
Professor.Id,
MySubquery.NumMatches
FROM
Professor
JOIN (
SELECT
Professor,
COUNT(*) AS NumMatches
FROM
Professor_expertise
WHERE
Subject_area_id IN (
SELECT Course_content.Subject_area_Id
FROM Course_content
WHERE Course_content.Course_Id = x
)
GROUP BY
Professor
) AS MySubquery
ORDER BY
MySubquery.NumMatches DESC
where x is the ID number corresponding to the course.
Here's what I suggest as your schema (primary keys bolded):
courses table: id and name
profs table: id and name
tags table: id and name
courseTags: tag_id and course_id (index on tag_id to speed up query)
profTags: tag_id and prof_id (index on tag_id to speed up query)
Then you can so something like:
SELECT profs.id, COUNT(*) AS matches
FROM profs, profTags, courseTags
WHERE profs.id=profTags.prof_id
AND profTags.tag_id=courseTags.tag_id
AND courseTags.course_id=[COURSE ID]
GROUP BY profs.id
ORDER BY matches DESC;
This query returns a list of prof IDs, ordered by the number of tag matches they have.
In the simplest form, I'd suggest having 5 tables:
tbl_CourseList
CourseId - int, PK, identity
CourseName - varchar(100)
tbl_CourseContent
ContentId - int, PK, identity
CourseId - int, FK
Type - varchar(25)
tbl_Professors
ProfessorId - int, PK, identity
ProfessorName - varchar(100)
tbl_ProfessorExpertise
ExpertiseId - int, PK, identity
ProfessorId - int, FK
ExpertiseType - varchar(25)
ExpertiseWeight - int
tbl_ProfessorCourses
CourseId
ProfessorId
Hopefully that is self-explanatory...

php and mysql user tracking and reporting

I currently have a table which consists of user information and lesson id; the table layout looks like:
----------------------------------------------------
|employeeID|numVisits|lessonID1|lessonID2|lessonID3|
----------------------------------------------------
|33388 |2 |1 |0 |3 |
and a lessons table which contains the information about the lesson:
------------------------------------------------------
|lessonID |cateogry |title |filepath |numberviews|
------------------------------------------------------
|1 |beginner |lesson |file:// |10 |
Within the lessonID fields in the user table is an integer which tracks how many times someone has clicked on a lesson. Now what I am trying to do is in a report I have the top 5 people who have visited the site and would like to then be able to drill down into what lessons they have clicked on.
Can anyone help with this? Or would restructuring the way the database is be an easier task?
Thanks
The way i have been looking at it so far is:
1 - get all the lessonID columns for a specific employeeID
2 - check which ones have a value greater than 0
3 - using the list in step 2 then query the lessonID on the user table for the corresponding title.
Step 1:
$sql = mysql_query("SELECT * FROM users
WHERE employeeID = 15110") or die(mysql_error());
$columns = mysql_num_fields($sql);
for($i = 0; $i < $columns; $i++) {
if(substr(mysql_field_name($sql, $i),0, 8) == "lessonID"){
$lessons[] = mysql_field_name($sql,$i).", ";
}
};
$lessonID = array_unique($lessons);
$l = substr("SELECT ".implode($lessonID)."", 0, -2)." FROM users WHERE employeeID = 15110";
This is where I am now at a loss, the above $l constructs the query to select all lessonID columns in the user table with a specific employeeID.
However I am at a loss as to where to go next with the query result.
Currently your employee can only ever take 3 lessons. You'd do better to normalize the data. Perhaps something like this:
employees
---------
emp_id
emp_name
etc.
visits
------
visit_id
visit_timestamp
emp_id
lessons
-------
lesson_id
lesson_title
etc.
emp_lessons
-----------
emp_id //FK to employees table
lesson_id //FK to lessons table
lesson_date
Then, when you want to know how often someone has visited,
SELECT count(*) FROM visits WHERE emp_id=x
And if you want to know how many times someone took lesson 1:
SELECT count(*) FROM emp_lessons WHERE lesson_id=1 AND emp_id=x;
You need to normalise your database design.
Consider a link table between your employee and lesson tables. This allows you to relate many employees to many lessons.
E.g.:
employee table
employee_id, num_visits
lesson table
lesson_id, category, title, filepath, numberviews
employee_lesson table
employee_id, lesson_id
The employee_id and lesson_id create a composite key.
Adding to the answers here's my two cents:
Considering the table structure I added below, you need the following queries to extract the data you need:
If you're tracking down the visits through table employee use the following, the result is the top 5 employees who visited the site:
SELECT * FROM employee ORDER BY visits ASC 0,5
if you're using the visit table:
SELECT employee.*, count(visit.visitId) as visits FROM employee, visit WHERE employee.employeeId = visit.employeeId GROUP BY employee.employeeId ASC 0,5
finallly, to check what lessons each employee has accessed, just use this:
SELECT * FROM employee WHERE employeeId = (SELECT employeeId FROM class GROUP BY lessonId)
You should reconsider the design, personally I'd do something like this:
**employee**
employeeId
employeeName
employeeLName
visits
lastVisit
If you want to track down each visit's date and time you should add a new table, visit, if you're not interested in the date and time, or just the last one, just add the fields to the employee table:
**visit**
visitId
visitDate
employeeId FK
**lesson**
lessonId
lessonName
lessonPath
lessonViews
**class** (or any name you see fit)
employeeId FK
lessonId FK
lessonDate (Last time the employee accessed the lesson)
Didn't have enough time to test the queries but I think they should at least point you in the right direction, hope it helps a bit :)

Categories