1

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

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

4

5 回答 5

2

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

于 2009-07-28T21:39:15.687 回答
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),这也是它的主键。

我希望我在回答这个问题时不要走得太远,但是当我尝试写较小的答案时,我一直不得不解开我之前的答案,而且发布这个似乎更简单。

于 2009-07-28T22:56:09.620 回答
1

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

于 2009-07-28T21:39:48.820 回答
1

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

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

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

于 2009-07-28T21:40:27.820 回答
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在命令中。

于 2009-07-28T21:59:42.087 回答