#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
, поскольку ясно, что вы хотите отслеживать активные, а не устаревшие элементы.