Целостность данных и ограничения

#php #mysql #validation #data-integrity

#php #mysql #проверка #целостность данных

Вопрос:

Используя следующую структуру таблицы:

 TABLE Something
(
    SomethingId             
    Name      
    DateCreated
    IsObsolete ('Y','N')       
    PRIMARY KEY (SomethingId)
    Foreign Key (SomethingTypeCode)
;


TABLE SomethingType
(
    SomethingTypeCode ('1','2','3')             
    Description             
    PRIMARY KEY (SomethingTypeCode)
);
  

При настройке PHP / MySQL есть ли какой-либо способ, которым я могу ограничить с помощью ограничения или индекса, что для каждого SomethingTypeCode (1, 2, 3), определенного в таблице Something, с ним может быть связан только один IsObsolete = N?

Я надеюсь, это объясняет, чего я пытаюсь достичь. Я просто не знаю, на что обратить внимание, чтобы решить эту проблему. Я хочу, чтобы целостность данных поддерживалась в максимально возможной степени в самой базе данных, а затем распространялась на PHP.


Редактировать:

В ответ на путаницу, которую я получаю с ответом VoteyDisciple.

Тип кода электронной почты: P = Личный, B = Бизнес, S = Школа

Вот мой дизайн:

введите описание изображения здесь

Это позволит пользователю иметь более одного типа электронной почты в заданном коде типа (т. е. 2 деловых письма) и избежать дублирования в базе данных и не требовать никаких нулей. Поскольку меня интересует только наличие одного активного электронного письма в каждой категории (того, которое будет использоваться системой), именно здесь вступает в игру IsObsolete. Я могу сохранить историю, избежать дублирования, избежать нулей и обеспечить уникальные адреса электронной почты, введенные в систему здесь.

Конечно, это также приводит к моей проблеме, как указано в исходном вопросе.

Подход ученика для голосования

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

введите описание изображения здесь

«Если для данного типа может быть только один» — Только один активен не каждый раз, а не только один в системе.
«Теперь ActiveId может быть нулевым» — я подчеркнул, что мне не нужны нули
«или это может указывать на конкретную запись Something». Тип определяет запись.

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

Ответ №1:

Вы должны быть в состоянии справиться с этим в триггере MySQL:

 DELIMITER $$
CREATE TRIGGER before_something_update 
BEFORE UPDATE ON Something
FOR EACH ROW BEGIN
   IF NEW.IsObsolete = 'N' THEN
      UPDATE Something SET IsObsolete = 'Y' WHERE SomethingId != NEW.SomethingId AND SomethingTypeID = NEW.SomethingTypeId;
   END IF; 
DELIMITER ;
  

И что-то похожее на insert.
Триггер проверит, пытаетесь ли вы установить для IsObselete значение N, и если да, то обновит все строки с одинаковым типом, которые не являются текущей строкой, и установит для них значение Y.

У вас могут возникнуть проблемы с взаимоблокировками, если вы используете InnoDB, но я не думаю, что у вас возникнут проблемы с MyISAM.

Комментарии:

1. спасибо за ответ. Не смогу углубиться в это до более позднего времени. С MySQL, поскольку вы можете определить только одно действие запуска, мне придется выбрать действие (Вставить или обновить) и упаковать в него то, что я могу, верно? Прямо сейчас это в основном затрагивает таблицы InnoDB, хотя некоторые из них могут быть изменены, возможно, при необходимости, и это было оправдано.

2. @enfield Да, вы правы, вам нужно будет упаковать все ваши правила в один или другой из триггеров, с InnoDB вы можете избежать взаимоблокировки, поэтому заблокируйте, поскольку вы не касаетесь строки, которую обновляете, или используйте триггер после обновления. Кроме того (хотя я не совсем уверен в этом), вам также может потребоваться убедиться, что вы не обновляете несколько элементов одного и того же типа в одной инструкции update .

Ответ №2:

Если для данного типа может быть только один, это свойство SomethingType , а не of Something .

 TABLE SomethingType
(
    SomethingTypeCode ('1','2','3')             
    ActiveId
    Description             
    PRIMARY KEY (SomethingTypeCode)
    Foreign Key (Something)
);
  

Теперь ActiveId может быть NULL (указывает на отсутствие не устаревшего Something для этого SomethingType), или это может указывать на конкретную Something запись.

И вы, очевидно, не можете поместить туда более одного идентификатора, поэтому у вас гарантированно будет либо ноль, либо один активный элемент.

Комментарии:

1. @VoteyDisciple Я не уверен, что это то, что мне нужно. Я знаю, что не хочу NULL s. Я также хочу сохранить реляционную разбивку (нормализацию), которая у меня есть между двумя таблицами. Хотя ваш способ является вариантом, если я вас правильно понимаю, он нарушает то, что у меня есть в моей базе данных.

2. Я понимаю, что вы предложили, но проблема в том, что то, что у вас есть, НЕ нормализовано. У вас есть поле, от SomethingTypeCode которого функционально зависит то, что хранится где-то еще, кроме SomethingType таблицы. Если вам не нужны NULL значения (т. Е. Всегда должно быть одно, Something которое устарело), вы можете просто указать столбец NOT NULL .

3. «проблема в том, что то, что у вас есть, НЕ нормализовано». Это смелое заявление, особенно с учетом того, что оно нормализовано.

4. Не соответствует заявленным требованиям. IsObsolete функционально зависит от SomethingTypeCode , и схема этого не отражает. Нормализация — это не просто вопрос сохранения свойств объекта в одном месте; функциональные зависимости — это то, что действительно имеет значение. Точно следуйте им, и в итоге вы получите нормализованную схему.

5. Я прочитал задом наперед IsObsolete = Y . Вместо этого я отредактирую свой ответ на замену ActiveId , поскольку ясно, что вы хотите отслеживать активные, а не устаревшие элементы.