2009-07-28 4 views
0

Я хотел бы знать, как вы можете предотвратить использование двух одинаковых тегов в таблице базы данных. Один сказал мне, что использует два закрытых ключа в таблице. Однако W3Schools -website говорит, что это невозможно.Чтобы предотвратить использование повторяющихся тегов в базе данных

Моя реляционная таблица

alt text http://files.getdropbox.com/u/175564/db/db7.png

Моя логическая таблица

alt text http://files.getdropbox.com/u/175564/db/db77.png

Контекст таблиц

alt text http://files.getdropbox.com/u/175564/db/db777.png

Как вы можете предотвратить использование повторяющихся тегов в вопросе?

ответ

2

Я обновил модель 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), что также является ее основным ключом.

Надеюсь, я не зашел слишком далеко, ответив на это, но когда я попытался написать меньшие ответы, мне все равно пришлось распутать мои более ранние ответы, и было проще просто опубликовать это.

+0

Спасибо за ваш ответ! - Я буду играть с этим :) –

+1

Кстати, все части NORMA, которые я использовал для этого, являются самыми легкими частями. Если вы хотите изучить его, учебники находятся на их сайте: http://www.ormfoundation.org/filesers/normalabs/default.aspx –

+0

Вы, кажется, имеете в виду, что база данных все еще нуждается в запросах UPDATE и DELETE. -- Спасибо за ссылку! –

2

Вы можете создать уникальное ограничение на (question_id, tag_name) в таблице тегов, которое гарантирует, что пара уникальна. Это означало бы, что один и тот же вопрос может не иметь один и тот же тег, прикрепленный более одного раза. Тем не менее, те же теги все равно могут применяться к различным вопросам.

+0

Пожалуйста, посмотрите мою попытку создать такое ограничение выше. –

+0

Вы имеете в виду это http://stackoverflow.com/questions/1202879/to-show-unique-constraint-for-two-columns-in-physical-erd –

+0

Я ответил на ваш вопрос в теме. –

1

Вы не можете создать два первичных ключа, но вы можете установить ограничение уникальности для индекса.

1

У вас может быть только один первичный ключ (я предполагаю, что это то, что вы подразумеваете под «закрытым» ключом), но этот ключ может быть составным ключом, состоящим из идентификатора вопроса и имени тега. В SQL, это будет выглядеть (в зависимости от SQL диалекта):

CREATE TABLE Tags 
(
    question_id int, 
    tag_name varchar(xxx), 
    PRIMARY KEY (question_id, tag_name) 
); 

Это позволит вам не может иметь тот же тег против того же вопроса.

+0

Спасибо за ваш ответ! --- Пожалуйста, посмотрите мою попытку конвертировать ваш код в PostgreSQL или Oracle. –

0

Я буду использовать 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.

+1

Я не уверен, что это правильно: если вы сделаете question_id единственным основным ключом, это будет означать, что на вопрос может быть только один тег! –

+0

@Ken: Спасибо за ваш комментарий! - Магнус тоже говорит, что он вызывает круговую ссылку на поток http://stackoverflow.com/questions/1195816/to-improve-sql-queries-in-ddl/1198220#1198220 –