Обновление промежуточной таблицы Best Practice PHP, MySQL - PullRequest
0 голосов
/ 05 июля 2018

Скажем, у меня много-много отношений между двумя учениками и предметами. Поэтому мы создаем промежуточную таблицу для отображения данных. Допустим, это ученики. Таблица student_subjects содержит 2 столбца: student_id & subject_id.

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

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

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

До недавнего времени, когда я обновлял объекты student_subjects (учащийся, выбирающий предметы), я удалял все предметы, которые у студента были, и вставлял новые.

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

Но недавно я добавил новый столбец в эту промежуточную таблицу как выбранный. Поэтому, если студент выбрал новые предметы и отменил выбор некоторых старых предметов, я добавил активные для новых и неактивные для отмены. (Я делаю это в PHP, получая новые выбранные предметы и ранее имевшие предметы. Затем сравниваю оба. Когда ученик выбирает предметы, я проверяю все предметы, которые ученик имеет [активные и неактивные]. Если вновь выбранные предметы ранее не были активными предметы я их активирую и добавляю новые.)

Какая лучшая практика для этого? Есть ли лучший способ добиться этого?

1 Ответ

0 голосов
/ 05 июля 2018

Я думаю, что ваш первый подход (удаление всех связанных строк и вставка новых записей) намного проще.

Если все еще нужно иметь поле selected, простым способом было бы создать уникальный составной индекс и использовать INSERT ... ON DUPLICATE KEY UPDATE. Это также может предотвратить случайную вставку одной и той же пары user_id и subject_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 = 1 и subject_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 |
+------------+------------+----------+---------------------+
...