0

Conditions are

  1. Many teachers to one subject relationship , that is one subject can be taught by more than one teachers, but one teacher can only teach one subject

  2. Many students to many subjects relationship, that is many students can take a common subject and one student can take many subjects.

  3. Many students to many batches relationship.

  4. Two batches can not be held in one time , so need a unique date field in batch table.

  5. Many batches to one subject relationship, that is only one subject is being taught per batch. But in other batches same subject which is taught in previous batch, can be repeated.

  6. The last condition is giving me problem, that is many batches to one teacher relationship , that is a teacher can teach in more than one batches and only one teacher for each batch.

My initial approach was as below

teacher table
-----------------------
id(PK)   name   email   subject_id(FK to subject.id)



subject table
-----------------------
id(PK)   name   description



student table
----------------------
id(PK)   name   location



batch table
----------------------
id(PK)   venue   teacher_id(FK to teacher.id)   date(unique)



student-batch table
-----------------------
id(PK)   batch_id(FK to batch.id)   student_id(FK to student.id)

And need to get the information lets say batch's id, teacher's name, students' name for a particular day.

But the problem is occuring when assigning teacher to batches, in each batch only one particular subject is being taught, and also one teacher can not teach more than one subject.

philipxy
  • 14,867
  • 6
  • 39
  • 83
user1906399
  • 753
  • 1
  • 13
  • 27

1 Answers1

1

You are missing a table associating subjects and students (per point 2):

// student [student_id] takes subject [subject_id]
takes(student_id, subject_id)

Notice that each base table has an associated statement template for statements about the business situation, parameterized by column names--its (characteristic) predicate. The rows that make the predicate true go in the table. Notice that the table definition looks like a shorthand for the predicate.

// teacher [id] named [name] with email [email] teaches subject [subject_id]
teacher(id, name, email, subject_id)

// subject [id] named [name] is [description]
subject(id, name, description)

// student [id] named [name] lives at [location])
student(id, name, location)

// batch [id] at venue [venue] was taught by teacher [teacher_id] on date [date]
batch(id, venue, teacher_id, date)

// student-batch [id] reports student [student_id] being in batch [batch_id]
student-batch(id, student_id, batch_id)
// CHECK student [student_id] takes the subject that is taught by the teacher of batch [batch_id]

But the problem is occuring when assigning teacher to batches, in each batch only one particular subject is being taught, and also one teacher can not teach more than one subject.

Since you seem stumped about this I will derive it in terms of how we can reason for table, constraint and query design. One way to express the constraint you want seems to be the commented CHECK above.

To express any table, constraint or query in SQL we first decide on its predicate. Then we can convert the predicate to shorthand. Then we can convert the shorthand to SQL.

Predicate:

student [student_id] takes the subject that is taught by the teacher of batch [batch_id]

Using base table predicates:

FOR SOME k.*, t.*, b.* (
    student_id = k.student_id AND batch_id = b.bid
AND student [k.student_id] takes subject [k.subject_id]
AND teacher [t.id] named [t.name] with email [t.email] teaches subject [t.subject_id] 
AND batch [b.id] at venue [b.venue] was taught by teacher [b.teacher_id] on date [b.date]
AND [k.subject_id] = [t.subject_id]
AND [t.id] = [b.teacher_id])

Using shorthands:

FOR SOME k.*, t.*, b.* (
    student_id = k.student_id AND batch_id = b.bid
AND takes(k.student_id, k.subject_id)
AND teacher(t.id, t.name, t.email, t.subject_id)
AND batch(b.id, b.venue, b.teacher_id, date)
AND k.subject_id = t.subject_id
AND t.id = b.teacher_id)

In a FROM each (possibly implicit) alias represents a table like the given base table name and/or subquery but with each column in its value & predicate renamed to alias.column.

We get the rows satisfying the AND of two predicates by JOINing the predicates' tables in SQL. If we want rows satisfying the AND of a condition then we use ON or WHERE in SQL.

A SELECT clause returns rows where FOR SOME values of dotted columns the returned (undotted) columns are equal to functions of dotted columns that satisfy the FROM predicate.

SQL: Replace statements by their tables, AND by JOIN or ON or WHERE, and outer FOR SOME & THERE EXISTS by SELECT:

SELECT t.student_id AS student_id, b.bid AS batch_id
FROM takes k JOIN teacher t JOIN batch b
WHERE k.subject_id = t.subject_id
AND t.id = b.teacher_id
AND student_id = t.student_id
AND batch_id = b.id

The table of rows satisfying the OR of two predicates is the UNION of their tables. For AND NOT we use EXCEPT (aka MINUS) (or a LEFT JOIN idiom). FOR SOME or THERE EXISTS over all columns can't be queried in SQL, but if we want to know whether there are rows satisfying a predicate then we can use EXISTS around a subquery with that predicate.

Suppose we want to constrain a base table so that every row satisfies a predicate on some columns. Ie FOR ALL columns IF they satisfy the base predicate THEN they satisfy the query predicate. Ie FOR ALL columns IF the row they form is in the base THEN it is in the query. So we require in SQL that NOT EXISTS (SELECT columns FROM base EXCEPT query). Or for each row in the base we require in SQL that EXISTS(query).

In Standard SQL you could CREATE ASSERTION CHECK(NOT EXISTS (SELECT student_id, batch_id FROM student-batch EXCEPT query)) or in a CREATE TABLE student-batch you could CHECK(EXISTS(query)). Unfortunately these are not supported by MySQL or most DBMSs. If you INSERT to student-batch after batch then you can require on trigger that EXISTS(query). Or you could add certain columns & composite FK (foreign key) constraints.

And need to get the information lets say batch's id, teacher's name, students' name for a particular day.

Now we are writing a query. We want rows where:

FOR k.*, t.*, b.*, s.*, sb.* (
    batch = b.id AND teacher = t.name AND student = s.name
AND takes(k.student_id, k.subject_id)
AND teacher(t.id, t.name, t.email, t.subject_id)
AND batch(b.id, b.venue, b.teacher_id, b.date)
AND student(s.id, s.name, s.location)
AND student-batch(sb.id, sb.student_id, sb.batch_id)
AND k.subject_id = t.subject_id
AND t.id = b.teacher_id
AND s.id = k.student_id
AND sb.student_id = k.student_id
AND sb.batch_id = b.id
AND @date = b.date)

This looks like the constraint predicate with different return columns and added lines. The SQL is just as directly translated. We add a join with student to get student names. We add a join with student-batch because the constraint doesn't deal with it; the contexts using the constraint query check whether student-batch (student_id, batch_id) subrows are in it.

SELECT b.id AS batch, t.name AS teacher, s.name AS student
FROM takes k JOIN teacher t JOIN batch b JOIN student s JOIN student-batch sb
WHERE ... AND @date = date

You could try an ON version:

SELECT b.id AS Batch, t.name AS Teacher, s.name AS Student
FROM takes k
JOIN teacher t ON k.subject_id = t.subject_id
JOIN batch b ON t.id = b.teacher_id
JOIN ...
WHERE @date = b.date
philipxy
  • 14,867
  • 6
  • 39
  • 83
  • very nice description. But how inserting data goes on? how to set foreign key options based on foreign key options of another field in the same table in phpmyadmin? if not possible atleaset how to get an error message when i click `go` after inserting data? Please take a look at [this](http://stackoverflow.com/questions/24738820/how-to-set-a-foreign-key-which-is-dependent-on-the-relation-of-other-two-tables) question i posted but yet no answers. – user1906399 Jul 15 '14 at 10:04