【问题标题】:To prevent the use of duplicate Tags in a database防止在数据库中使用重复的标签
【发布时间】:2010-11-14 21:01:00
【问题描述】:

我想知道如何防止在数据库表中使用两个相同的标签。 有人说我在一张表中使用两个私钥。但是,W3Schools 网站说这是不可能的。

我的关系表

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

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

【问题讨论】:

    标签: sql database ddl


    【解决方案1】:

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

    【讨论】:

    【解决方案2】:

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

    【讨论】:

      【解决方案3】:

      您只能有一个主键(我假设这就是您所说的“私人”键的意思),但该键可以是由问题 ID 和标记名称组成的 复合 键。在 SQL 中,它看起来像(取决于您的 SQL 方言):

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

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

      【讨论】:

      • 感谢您的回答! --- 请参阅我将您的代码转换为 PostgreSQL 或 Oracle 的尝试。
      【解决方案4】:

      我将使用 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

      【讨论】:

      • 我不确定这是否正确:如果您将 question_id 单独设置为主键,则意味着每个问题只能有一个标签!
      • @Ken:感谢您的评论! - Magnus 也说它会在线程 stackoverflow.com/questions/1195816/… 处引起循环引用
      【解决方案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),这也是它的主键。

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

      【讨论】:

      • 感谢您的回答! - 我会玩一会儿这个:)
      • 顺便说一句,我用于此的所有 NORMA 部分都是最简单的部分。如果你想学习它,教程在他们的网站上:ormfoundation.org/files/folders/normalabs/default.aspx
      • 您的意思似乎是数据库仍然需要 UPDATE 和 DELETE 查询。 -- 谢谢你的链接!
      • 您是否回复了错误的评论?关于查询,我什么都没说。
      • @Masi:不是查询。还记得你在另一个问题中喜欢的图表吗?那是一个简单的对象-角色建模图。我用于此答案的那个也很简单。我是说你可以很快地学习 NORMA 的那一部分。既然是 NORMA 一直在为我提供我发布的答案,如果你学会了它,你就会有自己的答案。
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2015-10-06
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多