Можно ли использовать ограничение SQL для предотвращения изменения конкретного значения при выполнении условия? - PullRequest
7 голосов
/ 08 июля 2011

Я знаю, что ограничения SQL могут заставить данные соответствовать критериям достоверности.Однако как насчет таких критериев, как «Оценка учащегося может быть обновлена ​​только в том случае, если флаг« окончательный вариант »имеет значение« ложь »?»Должны ли такие критерии обновления обрабатываться приложением?

Ответы [ 3 ]

4 голосов
/ 08 июля 2011

Триггер, ограничение и дополнительный столбец.

Начиная с конца:

  1. В дополнительном столбце хранится значение, которое должно быть «фиксированным»:

    ALTER TABLE ADD SavedGrade int
    
  2. Ограничение ограничивает изменение столбца Grade:

    ALTER TABLE Students
    ADD CONSTRAINT CK_Grade CHECK (Finalised = 'false' OR Grade = SavedGrade)
    
  3. Триггер обновляет дополнительный столбец при обновлении столбца Grade (ниже для SQL Server):

    CREATE TRIGGER StudentsFinaliseGrade
    ON Students AFTER INSERT, UPDATE
    AS
    IF UPDATE(Grade)
      UPDATE Students
      SET SavedGrade = i.Grade
      FROM inserted i
      WHERE i.ID = Students.ID
        AND i.Grade <> i.SavedGrade
    

Так что, пока Finalised = 'false', столбец Grade может быть изменен. Когда значение изменяется , значение немедленно сохраняется в столбце SavedGrade. (Мы обновляем SavedGrade напрямую, потому что в противном случае ограничение не позволило бы нам установить Finalised на 'true'.) Как только установлен Finalised, вы больше не можете изменять столбец Grade из-за ограничение.

4 голосов
/ 08 июля 2011

Краткий ответ: Нет, ограничения SQL не могут сами по себе предотвратить изменение столбца Grade, если для параметра Finalized установлено значение «true» (но разрешить изменение в противном случае).

Существует несколько видов ограничений SQL : CHECK, DEFAULT, NOT NULL, UNIQUE, Primary Key и Foreign Key.

Каждый из них может ограничивать или влиять на значения столбцов, по отдельности или в комбинации, но не может препятствовать обновлению значенийэто разрешено.В частности, ни одно из этих ограничений не может предотвратить UPDATE до Grade и / или Finalized на основе предыдущих значений Grade и Finalized.

Триггер UPDATE может сделать это: сравнить новые и старые значения Grade, и еслиони отличаются и Finalized = 'true', откатите ОБНОВЛЕНИЕ с пояснительным сообщением об ошибке.

Однако приложение может и должно применять такое «бизнес-правило» более изящно.Само правило может использовать некоторые пояснения относительно того, когда значение Finalized может быть изменено.Например, разрешено ли менять оценку и одновременно устанавливать Finalized = 'false'?Логика триггера может обрабатывать такие детали, и было бы разумно установить их как отказоустойчивые, в то же время делая правила явными где-то в приложении (frontend / middleware / backend).

0 голосов
/ 08 июля 2011

IMO, я бы сказал, что это должно быть сделано либо в приложении, либо в хранимой процедуре (возможно, в обеих), а не в качестве фактического ограничения (помимо прочего, в вашем конкретном примере оценка, которая «завершается», не это всегда означает, что это на самом деле окончательно).

Однако, если бы я реализовывал это как ограничение, я бы использовал ограничение CHECK (опять же, используя ваш пример)

CONSTRAINT chk_grade CHECK(grade between 0 AND 100 and finalized = 0)

Проверьте конкретный синтаксис этого, но это то, где я бы начал.

...