防止在数据库中使用重复的标记

时间:2009-07-28 21:34:01

标签: sql database ddl

我想知道如何防止在数据库表中使用两个相同的标记。 有人说我在表中使用两个私钥。然而,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

如何防止在问题中使用重复的标签?

5 个答案:

答案 0 :(得分:2)

您可以在tags表中的(question_id,tag_name)上创建唯一约束,这将确保是唯一的。这意味着同一个问题可能不会多次连接相同的标签。但是,相同的标签仍然适用于不同的问题。

答案 1 :(得分: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表,其中TAG_ID为主键。 TAG_NAME是一个单独的列,其上有唯一性约束,可防止重复标记。 QuestionTaggedTag表现在有(QUESTION_IDTAG_ID),这也是它的主键。

我希望我在回答这个问题时没有走得太远,但是当我试着写出较小的答案时,我不得不解开我之前的答案,发布这个答案似乎更简单。

答案 2 :(得分:1)

您不能创建两个主键,但可以在索引上放置唯一性约束。

答案 3 :(得分:1)

您只能拥有一个主键(我假设您的意思是“私钥”),但该键可以是由 id和tag-name组成的复合键。在SQL中,它看起来像(取决于您的SQL方言):

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

这将确保您不能对同一问题使用相同的标记。

答案 4 :(得分: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)是为了确保数据库中没有损坏的数据。

我从AUTO_INCREMENT中删除了QUESTION_ID因为我发现它会破坏我们的系统,因为一个问题不能有两个故意选择的标签。在其他情况下,标签会混淆。

我看到我们需要为约束命名。它的名称在命令中为no_duplicate_tag