Let's say I have 3 DB tables:
- teachers, with the following fields:
- subjects, with the following fields:
- teachers-subjects, with the following fields:
So, a relationship comes some teachers have subjects in common.
I've thought about the algorithm for querying:
For each record s in subjects table:
Select the count in teachers_subjects table.
If count is greater than 1
In teacher_subjects, get teacher_id's where subject_id is s.
Make the relationship pairs.
I'd like to get as output something like:
+----------+----------+---------------+
| Teacher1 | Teacher2 | Relationships |
+----------+----------+---------------+
| John | Larry | 10 |
| John | Samantha | 12 |
| Samantha | Larry | 9 |
| Ian | Louis | 3 |
+----------+----------+---------------+
And if I needed to retrieve which subjects made a relationship, we'd need to get something like:
+----+----------+----------+
| id | teacher1 | teacher2 |
+----+----------+----------+
| 1 | John | Larry |
| 2 | John | Samantha |
| 3 | Samantha | Larry |
| 4 | Ian | Louis |
+----+----------+----------+
And something like:
+-----+------------+
| id | subject |
+-----+------------+
| 1 | math |
| 1 | english |
| 1 | science |
| ... | ... |
| ... | ... |
| 4 | science |
| 4 | literature |
| 4 | databases |
+-----+------------+
Graphically, I'm representing this in a graph consulted over a web browser:
So when I hover one edge, it displays the relationships information.
I'll receive queries result over php programming, What such queries or stored procedure would produce me such required outputs?
These are my propositions for SQL.
Please remember, that every of these solutions is just a little modification from the previous ones.
First table
http://sqlfiddle.com/#!2/dc3f2/3
SELECT t1.name as 'Teacher1', t2.name as 'Teacher2', count(*) AS 'Relationships'
FROM teachers t1
JOIN teachers t2 ON t1.id > t2.id
JOIN teachers_subjects ts1 ON ts1.teacher_id = t1.id
JOIN teachers_subjects ts2 ON ts2.teacher_id = t2.id AND ts1.subject_id = ts2.subject_id
GROUP BY ts1.teacher_id, ts2.teacher_id;
Second table
I think it's working now.
http://sqlfiddle.com/#!2/dc3f2/22
SELECT @rownum := @rownum + 1 as id, relations.Teacher1, relations.Teacher2
FROM (SELECT t1.name as 'Teacher1', t2.name as 'Teacher2'
FROM teachers t1
JOIN teachers t2 ON t1.id > t2.id
JOIN teachers_subjects ts1 ON ts1.teacher_id = t1.id
JOIN teachers_subjects ts2 ON ts2.teacher_id = t2.id AND ts1.subject_id = ts2.subject_id
GROUP BY ts1.teacher_id, ts2.teacher_id) as relations,
(SELECT @rownum := 0) r;
Third table
http://sqlfiddle.com/#!2/dc3f2/27
SELECT id, subject
FROM
(SELECT @rownum := @rownum + 1 as id, relations.Teacher1, relations.Teacher2, relations.id1, relations.id2
FROM (SELECT t1.name as 'Teacher1', t2.name as 'Teacher2', t1.id as 'id1', t2.id as 'id2'
FROM teachers t1
JOIN teachers t2 ON t1.id > t2.id
JOIN teachers_subjects ts1 ON ts1.teacher_id = t1.id
JOIN teachers_subjects ts2 ON ts2.teacher_id = t2.id AND ts1.subject_id = ts2.subject_id
GROUP BY ts1.teacher_id, ts2.teacher_id) as relations,
(SELECT @rownum := 0) r) as rel
JOIN
(SELECT t1.id as 'id1', t2.id as 'id2', s.name as 'subject'
FROM teachers t1
JOIN teachers t2 ON t1.id > t2.id
JOIN teachers_subjects ts1 ON ts1.teacher_id = t1.id
JOIN teachers_subjects ts2 ON ts2.teacher_id = t2.id AND ts1.subject_id = ts2.subject_id
JOIN subjects s ON ts1.subject_id = s.id) as rel_subjects
ON rel.id1 = rel_subjects.id1 AND rel.id2 = rel_subjects.id2
ORDER BY id
On last thing. Please remember, that those pseudo keys for relationships are very changeable. That means that if you add new rows and remove some you will change those relationship's IDs. So not to get any errors you cannot use them in any storage column wherever in your database - just use them in SELECT queries.
Try this (You should load some sample data in SQLFiddle for better testing)
SELECT t1.`name` AS teacher1, t2.`name` AS teacher2, count(*)
FROM teachers AS t1
JOIN teachers AS t2
ON t1.id > t2.id
JOIN teacher_subjects AS ts1
ON ts1.teacher_id = t1.id
JOIN teacher_subjects AS ts2
ON ts2.teacher_id = t2.id
AND ts2.subject_id = ts1.subject_id
GROUP BY teacher1, teacher2
ORDER BY COUNT(*) DESC;