Эффективный способ обновить таблицу отношений SQL

Скажем, у меня есть три правильно нормализованных таблицы. Один из людей, один из квалификаций и один сопоставление людей с квалификациями:

Люди:

id | Name
----------
1  | Alice
2  | Bob

Степени:

id | Name
---------
1  | PhD
2  | MA

От людей до ученых степеней:

person_id | degree_id
---------------------
1         | 2         # Alice has an MA
2         | 1         # Bob has a PhD

Итак, мне нужно обновить это сопоставление через мой веб-интерфейс. (Я допустил ошибку. У Боба степень бакалавра, а не доктор философии, а Элис только что получила степень бакалавра технических наук.)

Существует четыре возможных состояния этих отображений отношений «один ко многим»:

  • было верно раньше, теперь должно быть ложным
  • было ложным раньше, теперь должно быть правдой
  • было правдой раньше, должно оставаться правдой
  • было ложным раньше, должно оставаться ложным

что я не хочу делать, так это читать значения из четырех флажков, а затем четыре раза обращаться к базе данных, чтобы сказать: «Был ли у Боба BA раньше? Ну, теперь он есть». «Был ли у Боба докторская степень раньше? Потому что у него ее больше нет» и так далее.

Как другие люди решают эту проблему?

Мне любопытно посмотреть, придет ли кто-то еще к тому же решению, что и я.

ОБНОВЛЕНИЕ 1: onedaywhen предлагает то же самое, что пришло мне в голову — просто удалите все старые записи, правильные или нет, и ВСТАВЬТЕ новые.

ОБНОВЛЕНИЕ 2. Картофельные пилинги предлагают добавить в форму некоторый код, в котором хранится исходное значение поля, которое можно сравнить с новым значением при отправке.


person AmbroseChapel    schedule 15.06.2010    source источник
comment
какие элементы управления в вашем веб-интерфейсе? Все флажки для значений в таблице «Люди и градусы»? Одно обновление для одного человека?   -  person IsmailS    schedule 15.06.2010
comment
Я надеюсь, что этот ответ поможет stackoverflow.com/questions/2273815/   -  person IsmailS    schedule 15.06.2010
comment
Вы можете использовать разные стратегии в зависимости от вашей конкретной базы данных и версии.   -  person josephj1989    schedule 15.06.2010
comment
Этот ответ действительно решает проблему, но только для определенного типа SQL-сервера, если я не запутался.   -  person AmbroseChapel    schedule 15.06.2010
comment
MERGE предназначен для SQL Server 2008. Но пример BEGIN TRAN — COMMIT будет работать для предыдущих версий.   -  person potatopeelings    schedule 15.06.2010
comment
Да, Исмаил, это флажки. И josephj, я надеюсь получить общий комментарий по этому вопросу, а не что-то конкретное по реализации. Я обычно использую MySQL.   -  person AmbroseChapel    schedule 16.06.2010
comment
Я вижу это сейчас. Но я не могу использовать MERGE в MySQL, поэтому я все еще ищу общий ответ, спасибо.   -  person AmbroseChapel    schedule 16.06.2010
comment
В этом случае вы могли бы пометить свой вопрос с помощью MySQL. Я сделаю это.   -  person IsmailS    schedule 16.06.2010


Ответы (2)


Логически UPDATE — это DELETE, за которым следует INSERT (учитывайте, что триггеры SQL Server могут обращаться к логическим таблицам с именами inserted и deleted, но нет таблицы updated). Таким образом, вы должны иметь возможность обращаться к базе данных только дважды, то есть сначала DELETE всех строк (правильных или нет) для Боба, а затем INSERT всех правильных строк для Боба.

Если вы хотите обратиться к базе данных только один раз, рассмотрите возможность использования стандартного SQL MERGE, при условии, что ваша СУБД поддерживает его (SQL Server представил его в 2008 году).

person onedaywhen    schedule 15.06.2010
comment
Ага! Сначала DELETE, а затем INSERT показались мне самым элегантным способом обойти сложность. Кто-нибудь хочет прокомментировать? onedaywhen ответ не имеет ни положительных, ни отрицательных голосов ... - person AmbroseChapel; 16.06.2010

Предполагая, что пользовательский интерфейс представляет собой сетку флажков (1. в комментарии Исмаила к вопросу)

           MA      PhD    
Alice      x 
Bob                 x

где x представляет отмеченные флажки. Я бы использовал интерфейсный скрипт для отправки обратно на сервер только изменений. Затем выполните INSERT и DELETE в People-to-степенях в рамках одной транзакции или MERGE (как указано в ссылке Ismail)

BEGIN TRAN
INSERT query
DELETE query
COMMIT

Вы должны передать запрос INSERT (и DELETE) список идентификаторов людей, пар идентификаторов степени, например. В вашем примере запрос INSERT будет одной парой (2,2), а запрос DELETE — одной парой (2,1).

person potatopeelings    schedule 15.06.2010
comment
Как интерфейсный скрипт будет отправлять только изменения? Вы говорите, что для каждого флажка будет соответствующий ‹input type=hidden› с исходным значением? - person AmbroseChapel; 16.06.2010
comment
Это один из способов сделать это. Другие способы: 1. Добавьте дополнительный атрибут к флажку со старым значением, к которому вы позже сможете получить доступ с помощью .getAttribute 2. Добавьте событие onclick к каждому флажку, который отслеживает изменения 3. Создайте строку/массив сетки values ​​onload страницы, а onsubmit сравнивает отправленные значения с этими (строка, созданная при загрузке). - person potatopeelings; 16.06.2010
comment
Я старой школы. Я не думал полагаться на язык сценариев на стороне клиента! - person AmbroseChapel; 16.06.2010