更新中介表最佳实践PHP,MySQL

时间:2018-07-05 16:19:03

标签: php mysql database time-complexity

说我在两张桌子的学生和科目之间有多对多的关系。因此,我们创建了一个中间表来映射数据。可以说这是students_subjects。 students_subjects表有两列,分别是student_id和subject_id。

+------------+--------------+
| student_id | student_name |
+------------+--------------+
|            |              |
+------------+--------------+

+------------+--------------+
| subject_id | subject_name |
+------------+--------------+
|            |              |
+------------+--------------+

+------------+------------+
| student_id | subject_id |
+------------+------------+
|            |            |
+------------+------------+

直到最近一段时间,students_subjects(学生选择学科)有更新,我所做的是删除所有学生插入了新学科的学科。

+------------+------------+----------+
| student_id | subject_id | selected |
+------------+------------+----------+
| 1          | 2          | 1        |
+------------+------------+----------+
| 1          | 2          | 0        |
+------------+------------+----------+

但是最近我选择了在此中介表中添加新列。因此,如果学生选择了新的科目并取消选择了一些旧的科目,那么我为新科目添加了活动,而对取消选择的科目则添加了非活动。 (我在PHP中通过获取新选择的科目和先前拥有的科目来进行此操作。然后将两者进行比较。当学生选择科目时,我会检查该学生具有的所有主题([活动和不活动]。我将它们激活并添加新的主题。)

最佳做法是什么?我有更好的方法实现这一目标吗?

1 个答案:

答案 0 :(得分:1)

我确实认为您的第一种方法(删除所有关联的行并插入新条目)要简单得多。

如果仍然希望拥有selected字段,一种简单的方法是创建唯一的复合索引并使用INSERT ... ON DUPLICATE KEY UPDATE。这也可以防止意外插入相同的user_idsubject_id对。首先创建索引:

ALTER TABLE `students_subjects` ADD UNIQUE `unique_student_subject`(`student_id`, `subject_id`);

然后,只需将学生的selected字段更新为0并插入学生选择的主题即可。使用PDO的示例:

$studentId = 1;
$newlySelectedSubjects[] = ['subject_id' => 3];
$newlySelectedSubjects[] = ['subject_id' => 4];

$db = new PDO("connection string here", $username, $password);
$db->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);

$db->beginTransaction();

try{
    $qry = 'UPDATE students_subjects SET selected = 0 WHERE student_id = :studentId';

    $stmt = $db->prepare($qry);
    $stmt->execute(['studentId' => $studentId]);

    $insertQry = 'INSERT INTO students_subjects (student_id, subject_id, selected)' 
                 .'VALUES (:studentId, :subjectId, 1) '
                 .'ON DUPLICATE KEY UPDATE '
                 .'selected = 1';
    $insertStmt = $db->prepare($insertQry);

    foreach ($newlySelectedSubjects as $subject) {

        $params = ['studentId' => $studentId, 'subjectId' => $subject['subject_id']];
        $insertStmt->execute($params);
    }
    $db->commit();
} catch (PDOException $e) {
    //do something with exception
    $db->rollBack();
}

将发生的情况是,如果表中已经存在student_id = 1subject_id = 3的学生,则selected字段为设置为1,否则将插入新记录。

如果您需要跟踪用户主题选择和取消选择,我建议实施某种审计跟踪,并保留students_subjects仅保留学生和主题之间的关系。借助mysql TRIGGER可以更容易。审核跟踪表的简化示例:

+------------+------------+----------+---------------------+
| student_id | subject_id | action   | action_datetime     |
+------------+------------+----------+---------------------+
| 1          | 2          | remove   | 2018-01-01 00:01:23 |
+------------+------------+----------+---------------------+
| 1          | 4          | add      | 2018-01-01 01:07:45 |
+------------+------------+----------+---------------------+