Для предотвращения использования дубликатов тегов в базе данных
Я хотел бы знать, как вы можете предотвратить использование двух одинаковых тегов в таблице базы данных. Один сказал мне, что используют два закрытых ключа в таблице. Однако сайт W3Schools утверждает, что это невозможно.
Моя реляционная таблица
http://files.getdropbox.com/u/175564/db/db7.png
Моя логическая таблица
http://files.getdropbox.com/u/175564/db/db77.png
Контекст таблиц
http://files.getdropbox.com/u/175564/db/db777.png
Как вы можете предотвратить использование дублирующих тегов в вопросе?
5 ответов
Я обновил свою модель NORMA, чтобы она более точно соответствовала вашей диаграмме. Я вижу, где вы допустили несколько ошибок, но некоторые из них могли быть связаны с моей более ранней моделью.
Я обновил эту модель, чтобы предотвратить дублирование тегов. Это не имело значения прежде. Но так как вы хотите, вот оно (для Postgres):
START TRANSACTION ISOLATION LEVEL SERIALIZABLE, READ WRITE;
CREATE SCHEMA so;
SET search_path TO SO,"$user",public;
CREATE DOMAIN so.HashedPassword AS
BIGINT CONSTRAINT HashedPassword_Unsigned_Chk CHECK (VALUE >= 0);
CREATE TABLE so."User"
(
USER_ID SERIAL NOT NULL,
USER_NAME CHARACTER VARYING(50) NOT NULL,
EMAIL_ADDRESS CHARACTER VARYING(256) NOT NULL,
HASHED_PASSWORD so.HashedPassword NOT NULL,
OPEN_ID CHARACTER VARYING(512),
A_MODERATOR BOOLEAN,
LOGGED_IN BOOLEAN,
HAS_BEEN_SENT_A_MODERATOR_MESSAGE BOOLEAN,
CONSTRAINT User_PK PRIMARY KEY(USER_ID)
);
CREATE TABLE so.Question
(
QUESTION_ID SERIAL NOT NULL,
TITLE CHARACTER VARYING(256) NOT NULL,
WAS_SENT_AT_TIME TIMESTAMP NOT NULL,
BODY CHARACTER VARYING NOT NULL,
USER_ID INTEGER NOT NULL,
FLAGGED_FOR_MODERATOR_REMOVAL BOOLEAN,
WAS_LAST_CHECKED_BY_MODERATOR_AT_TIME TIMESTAMP,
CONSTRAINT Question_PK PRIMARY KEY(QUESTION_ID)
);
CREATE TABLE so.Tag
(
TAG_ID SERIAL NOT NULL,
TAG_NAME CHARACTER VARYING(20) NOT NULL,
CONSTRAINT Tag_PK PRIMARY KEY(TAG_ID),
CONSTRAINT Tag_UC UNIQUE(TAG_NAME)
);
CREATE TABLE so.QuestionTaggedTag
(
QUESTION_ID INTEGER NOT NULL,
TAG_ID INTEGER NOT NULL,
CONSTRAINT QuestionTaggedTag_PK PRIMARY KEY(QUESTION_ID, TAG_ID)
);
CREATE TABLE so.Answer
(
ANSWER_ID SERIAL NOT NULL,
BODY CHARACTER VARYING NOT NULL,
USER_ID INTEGER NOT NULL,
QUESTION_ID INTEGER NOT NULL,
CONSTRAINT Answer_PK PRIMARY KEY(ANSWER_ID)
);
ALTER TABLE so.Question
ADD CONSTRAINT Question_FK FOREIGN KEY (USER_ID)
REFERENCES so."User" (USER_ID) ON DELETE RESTRICT ON UPDATE RESTRICT;
ALTER TABLE so.QuestionTaggedTag
ADD CONSTRAINT QuestionTaggedTag_FK1 FOREIGN KEY (QUESTION_ID)
REFERENCES so.Question (QUESTION_ID) ON DELETE RESTRICT ON UPDATE RESTRICT;
ALTER TABLE so.QuestionTaggedTag
ADD CONSTRAINT QuestionTaggedTag_FK2 FOREIGN KEY (TAG_ID)
REFERENCES so.Tag (TAG_ID) ON DELETE RESTRICT ON UPDATE RESTRICT;
ALTER TABLE so.Answer
ADD CONSTRAINT Answer_FK1 FOREIGN KEY (USER_ID)
REFERENCES so."User" (USER_ID) ON DELETE RESTRICT ON UPDATE RESTRICT;
ALTER TABLE so.Answer
ADD CONSTRAINT Answer_FK2 FOREIGN KEY (QUESTION_ID)
REFERENCES so.Question (QUESTION_ID) ON DELETE RESTRICT ON UPDATE RESTRICT;
COMMIT WORK;
Обратите внимание, что теперь есть отдельная таблица тегов с TAG_ID
в качестве первичного ключа. TAG_NAME
это отдельный столбец с ограничением уникальности, предотвращающим дублирование тегов. QuestionTaggedTag
таблица сейчас есть (QUESTION_ID
, TAG_ID
), который также является его первичным ключом.
Надеюсь, я не зашел слишком далеко, чтобы ответить на этот вопрос, но когда я пытался писать меньшие ответы, мне приходилось распутывать свои предыдущие ответы, и было проще просто опубликовать это.
Вы можете создать уникальное ограничение для (question_id, tag_name) в таблице тегов, что обеспечит уникальность пары. Это означает, что к одному и тому же вопросу не может быть прикреплен один и тот же тег более одного раза. Тем не менее, один и тот же тег может применяться к разным вопросам.
Вы не можете создать два первичных ключа, но вы можете наложить ограничение уникальности на индекс.
У вас может быть только один первичный ключ (я полагаю, это то, что вы подразумеваете под "закрытым" ключом), но этот ключ может быть составным ключом, состоящим из идентификатора вопроса и имени тега. В SQL это будет выглядеть (в зависимости от вашего диалекта SQL):
CREATE TABLE Tags
(
question_id int,
tag_name varchar(xxx),
PRIMARY KEY (question_id, tag_name)
);
Это гарантирует, что вы не можете иметь один и тот же тег на один и тот же вопрос.
Я буду использовать PostgreSQL или Oracle.
Я чувствую, что следующее соответствует коду Кена, который предназначен для MySQL.
CREATE TABLE Tags
(
QUESTION_ID integer FOREIGN KEY REFERENCES Questions(QUESTION_ID)
CHECK (QUESTION_ID>0),
TAG_NAME nvarchar(20) NOT NULL,
CONSTRAINT no_duplicate_tag UNIQUE (QUESTION_ID,TAG_NAME)
)
Я добавил несколько дополнительных мер в запрос. Например, CHECK (USER_ID>0)
чтобы убедиться, что нет поврежденных данных в базе данных.
Я бросил AUTO_INCREMENT
из этого QUESTION_ID
потому что я вижу, что это сломало бы нашу систему, поскольку один вопрос не может иметь два специально выбранных тега. В других случаях теги будут перепутаны.
Я вижу, что нам нужно дать имя для ограничения. Его имя no_duplicate_tag
в команде.