2009-07-28 62 views
0

我想知道如何防止在數據庫表中使用兩個相同的標籤。 有人說我在表中使用兩個私鑰。然而,W3School-網站說這是不可能的。爲了防止在數據庫中使用重複的標籤

我的關係表

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),這也是它的主要關鍵。

我希望我沒有去回答這個太遠了,但是當我試着寫較小的答案,我一直有解開我剛纔的回答,似乎只是簡單發佈此。

2

您可以在標記表中爲(question_id,tag_name)創建唯一約束,這將確保是唯一的。這意味着相同的問題可能不會有多次附加相同的標籤。但是,相同的標籤仍然適用於不同的問題。

+0

請看看我試圖創建上述這樣的限制。 – 2009-07-28 22:01:26

+0

你的意思是這個http://stackoverflow.com/questions/1202879/to-show-unique-constraint-for-two-columns-in-physical-erd – 2009-08-01 12:59:11

+0

我回答你的問題的線程。 – 2009-08-02 18:18:31

1

您不能創建兩個主鍵,但可以在索引上放置唯一性約束。

1

您只能擁有一個主鍵(我假設您指的是「私人」鍵),但該鍵可以是複合鍵,其中包含問題ID和標記名稱。在SQL中,它看起來(取決於您的SQL方言),如:

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

這將確保你不能有針對同一問題,同一個標籤。

+0

謝謝你的回答! ---請參閱我的嘗試將您的代碼轉換爲PostgreSQL或Oracle。 – 2009-07-28 22:00:27

0

我將使用PostgreSQL或Oracle。

我覺得以下是Ken的代碼,它是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)用於確保數據庫中沒有損壞的數據。

我從這個QUESTION_ID跌出AUTO_INCREMENT,因爲我看到,它會破壞我們的系統,因爲一個問題不能再有兩個特意選擇的標籤。另外,標籤會混在一起。

我看到我們需要給出約束的名稱。它的名字是no_duplicate_tag在命令中。