Detecting relationships among MySQL DB records

2019-07-24 00:34发布

问题:

Let's say I have 3 DB tables:

  1. teachers, with the following fields:
    • id
    • name
  2. subjects, with the following fields:
    • id
    • name
  3. teachers-subjects, with the following fields:
    • teacher_id
    • subject_id

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?

回答1:

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.



回答2:

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;


标签: php mysql mysqli