1

I am trying to figure out how to go about with this scenario in mySQL -

There are three tables - t_student, t_teacher, t_result structure of the tables (basically columns in each of them) are as below:

t_student:
s_id, s_name, s1, s2, s3

where s_id is the primary key, s_name is student name, (s1,s2,s3) are subjects like math, phy, chem etc..

t_teacher:
t_id, t_name, s1, s2, s3

where t_id is the primary key, t_name is teacher name, (s1,s2,s3) are subjects like math, phy, chem etc..

t_result:
r_id, s_name, t_name, count

where r_id is the primary key, s_name is the student name (from student table), t_name is the teacher name (from teacher table) and count gives count (more on that in a moment)

Now, what I would like to do is as below:

there could be any number of records in student and teacher table, and none as of now in the results table. Now, using mySQL I would like to scan the contents of student table, and for each record in this table, i would like to pickup:

s1 and then compare the value with (s1,s2,s3) columns in teacher table s2 and then compare the value with (s1,s2,s3) columns in teacher table s3 and then compare the value with (s1,s2,s3) columns in teacher table

and the get the number of matching values and store in count.

For more clarity, if for the first record in student table, s1, s2 and s3 are "phy", "chem" and "maths", and if the first record in teacher table is "maths", "phy", "computer", then in this case, student.s1 matches with teacher.s2 - so now count is 1. then student.s2 is matched against the s1,s2,s3 in teacher table, but match is 0, so count is kept 1; again student.s3 is matched against s1,s2,s3 in teacher table,this time it matches with teacher.s1, so count is incremented to 2. So at the end of comparison of first record in student table with first record of teacher table, i get the count=2. Now i would insert a row into the result table, with student name, teacher name, and the so obtained count.

Basically I want to get the number of s1,s2,s3 match between the student table and teacher table, for each row in student table and then put this into the result table.

I know only basic operations in mysql- like selecting inserting deleting etc.. I am assuming that such an operation would require more than that, something like plsql and stored procedure?

FYI, I am using phpmyadmin, and the tables are stored there. I would be using php to fetch the results from the table,and to execute these queries.

Please let me know the approach for this.

Thank You!

kallakafar
  • 725
  • 3
  • 11
  • 27

4 Answers4

1

Your database design needs some work. Start by normalising your data, moving the repeated subject columns out of the teacher and student tables. You could do this by creating the following tables:

CREATE TABLE t_subjects ( subject_id INT, name VARCHAR(30) );
CREATE TABLE t_teacher_subjects ( teach_id INT, subject_id INT);
CREATE TABLE t_student_subjects ( student_id INT, subject_id INT);

Remove the s1, s2, s3 columns from teacher and student, and you will then be able to populate your results table (provided it has an auto_increment primary key) in a single query - something like this:

insert into t_result (s_name, t_name, count) 
select t_teacher.t_name, t_student.s_name, count(*) as c from
t_teacher_subjects 
    inner join t_student_subjects on t_teacher_subjects.subject_id = t_student_subjects.subject_id
    inner join t_teacher on t_teacher_subjects.teach_id = t_teacher.t_id
    inner join t_student on t_student_subjects.student_id = t_student.s_id
group by t_teacher.t_name, t_student.s_name;
Alex
  • 995
  • 9
  • 11
  • thanks, but again I cannot move the subjects out from the other tables. In fact, i the student table subjects and teacher table subjects are totally different, and not related between themselves. These two tables are independent. My requirement is matching the subject to see if it exists in any of the teacher table columns, and to get the number of matching subjects in the Count. I think i have made my original post slightly confusing, but then the tables cannot be normalised further. any way to get the count without normalising? – kallakafar Oct 13 '12 at 19:05
1

You should modify your tables to

t_student:
s_id, s_name, s_s

and

t_teacher:
t_id, t_name, t_s

and split your s1, s2, s3 to separate rows. Then you can do a simple join between t_student and t_teacher.

Olaf Dietsche
  • 72,253
  • 8
  • 102
  • 198
0

Actually, you don't have to need any procedural code to resolve this. The approach is called "normalization". You need more than one table to represent the subjects for a teacher, so that s1, s2, s3 values go to a single column in a separate table, which is in a foreign key relationship with the teacher table. Same for the other relationships. (That's why the term "relational database" in the first place.)

A related discussion is here: DB Design: 1st Normal Form and Repeating Groups.

Edit

Looks like an assignment rather than a production issue :). Anyway, you still may try a convoluted pure-SQL approach to normalize in the query rather than in the schema. Weird but not impossible.

Here's the essence of the trick. Use this as a subquery to get a normalized representation of your data:

select s_id, s_name, s1 s from t_student
union
select s_id, s_name, s2 s from t_student
union
select s_id, s_name, s3 s from t_student
Community
  • 1
  • 1
full.stack.ex
  • 1,747
  • 2
  • 11
  • 13
  • thanks for looking into this, but I guess you misunderstood my requirement. The records in both tables are different and come from different sources (on a high level), and are not really dependent. So the third table - results table is really required. Probably I m not fully explaining things, but believe me this is not about normalization. I just would like to know how to determine the COUNT by matching each of those student.(s1,s2,s3) with teacher.(s1,s2,s3). Thanks again. – kallakafar Oct 13 '12 at 18:49
  • Chances are, we are all missing the point. But it still looks like all the answers here are essentially about the same: eliminating a repeating group of s1, s2, s3 and using a one-to-many relationship instead. It's normalization indeed. – full.stack.ex Oct 13 '12 at 19:15
  • yup.. i guess my question is not clear enough! i think i would need to write procedure and then get the matching count and then enter into the result table. looking into that approach now. anyway, thanks for helping :) – kallakafar Oct 13 '12 at 19:35
  • Added another answer with a query that normalizes your data internally. – full.stack.ex Oct 13 '12 at 20:52
0

Well. Thank you for this challenge. A nice mental exercise :).

Here's the query; just convert it into an insert:

select s_name, t_name, count(*) cnt from
(
select s.s_name, s.s s_s, t.t_name, t.s t_s from
(
select s_id, s_name, s1 s from t_student
union
select s_id, s_name, s2 s from t_student
union
select s_id, s_name, s3 s from t_student
) s
inner join
(
select t_id, t_name, s1 s from t_teacher
union
select t_id, t_name, s2 s from t_teacher
union
select t_id, t_name, s3 s from t_teacher
) t
on t.s = s.s
) m
group by s_name, t_name
;

Edit: Actual run:

mysql> select * from t_student;
+------+--------+------+------+------+
| s_id | s_name | s1   | s2   | s3   |
+------+--------+------+------+------+
|    1 | st1    | qqq  | www  | eee  |
|    2 | st2    | 111  | 222  | 333  |
|    3 | st3    | zzz  | xxx  | ccc  |
+------+--------+------+------+------+
3 rows in set (0.00 sec)

mysql> select * from t_teacher;
+------+--------+------+------+------+
| t_id | t_name | s1   | s2   | s3   |
+------+--------+------+------+------+
|    1 | te1    | qqq  | www  | eee  |
|    2 | te2    | 111  | 222  | nnn  |
|    3 | te3    | zzz  | nnn  | nnn  |
+------+--------+------+------+------+
3 rows in set (0.00 sec)

mysql> select s_name, t_name, count(*) cnt from
    -> (
    -> select s.s_name, s.s s_s, t.t_name, t.s t_s from
    -> (
    -> select s_id, s_name, s1 s from t_student
    -> union
    -> select s_id, s_name, s2 s from t_student
    -> union
    -> select s_id, s_name, s3 s from t_student
    -> ) s
    -> inner join
    -> (
    -> select t_id, t_name, s1 s from t_teacher
    -> union
    -> select t_id, t_name, s2 s from t_teacher
    -> union
    -> select t_id, t_name, s3 s from t_teacher
    -> ) t
    -> on t.s = s.s
    -> ) m
    -> group by s_name, t_name
    -> ;

+--------+--------+-----+
| s_name | t_name | cnt |
+--------+--------+-----+
| st1    | te1    |   3 |
| st2    | te2    |   2 |
| st3    | te3    |   1 |
+--------+--------+-----+
3 rows in set (0.00 sec)
full.stack.ex
  • 1,747
  • 2
  • 11
  • 13
  • hmm.. nice work, but still none of the answers are what I am looking for. :) – kallakafar Oct 13 '12 at 21:19
  • For more clarity, if for the first record in student table, s1, s2 and s3 are "phy", "chem" and "maths", and if the first record in teacher table is "maths", "phy", "computer", then in this case, student.s1 matches with teacher.s2 - so now count is 1. then student.s2 is matched against the s1,s2,s3 in teacher table, but match is 0, so count is kept 1; again student.s3 is matched against s1,s2,s3 in teacher table,this time it matches with teacher.s1, so count is incremented to 2. – kallakafar Oct 13 '12 at 21:20
  • So at the end of comparison of first record in student table with first record of teacher table, i get the count=2. Now i would insert a row into the result table, with student name, teacher name, and the so obtained count. – kallakafar Oct 13 '12 at 21:21
  • 1
    full.stack.ex's answer will give the result you described. By pivoting all subject columns in each of the students and teacher table, you have a replica of the normalised data, with the ability for one student to match a teacher multiple times, which will yield the result you are looking for. – Alex Oct 13 '12 at 22:31
  • I've actually tried it with MySQL. Have you? I've edited the answer with the test data and the result. How is it different from what you want? – full.stack.ex Oct 14 '12 at 09:17