帮助主键和唯一约束

时间:2010-02-13 14:25:10

标签: sql mysql database-design

在表格中我有3列:

id
tag1
tag2

id是主键。

我只想在该表中使用一个唯一的tag1-tag2组合。

例如,如果一个条目如下:

id: 1
tag1: cat
tag2: dog

我不希望插入下面的第二个条目:

id: 2
tag1: cat
tag2: dog

所以我制作了所有3列主键,但问题是第二个条目会被插入,因为它看起来是所有3个组合的组合。

我如何解决这个问题,以便只有tag1和tag2的组合是唯一的?


更新:我在tag1和tag2上添加了一个独特的约束。但是,它仍然可以插入:

id: 3
tag1: dog
tag2: cat

有没有办法阻止这种情况?

6 个答案:

答案 0 :(得分:4)

您应该将ID作为主键,然后可以为tag1和tag2创建唯一约束:

ALTER TABLE my_table ADD CONSTRAINT uc_tags UNIQUE (tag1, tag2)

使用唯一约束,您将保证永远不会有两行具有重复的tag1和tag2值。


修改

除了上次更新之外,您无法使用唯一约束强制执行此更新。请记住,对于数据库,(tag1 = dog,tag2 = cat)的记录与(tag1 = cat,tag2 = dog)的记录完全不同。

可能最好的办法是重新设计数据库架构,如下所示:

  
      
  • 表“tags”
  •   
  • 表“消息”(或您正在标记的任何内容)
  •   
  • 表“tags_messages”包含以下字段(message_id,tag_id)
  •   

然后,您只需将“tag_messages”表的(message_id,tag_id)设置为主键即可。这将自动强制执行不存在任何带有重复标记的消息。

一些示例数据:

Table: messages

message_id   |   title
-------------+------------------
1            |   some message
2            |   another message


Table: tags

tag_id       |   tags
-------------+-------------------
1            |   cat
2            |   dog
3            |   duck
4            |   horse


Table: messages_tags

message_id   |   tag_id
-------------+-------------------
1            |   1
1            |   2
2            |   3
2            |   4
2            |   1

答案 1 :(得分:1)

您可以将主键保留在“id”列中,并在“tag1”和“tag2”列上添加唯一约束。请参阅此link

答案 2 :(得分:1)

添加一个结合了tag1和tag2的唯一索引。

http://dev.mysql.com/doc/refman/5.1/en/create-index.html

答案 3 :(得分:1)

根据您是否以及何时需要在其他表中使用“唯一记录”,可以认为您的“id”字段是不必要的。 (这里的ID是代理键)如果您不在另一个表中使用“id”字段,那么将主键设置为(tag1,tag2)并删除“id”列真的更有意义在一起。

答案 4 :(得分:0)

我想问题是,你为什么这样做呢?了解商业原因会有所帮助。

您始终可以SELECT DISTINCT仅获取具有唯一值的行。

答案 5 :(得分:0)

如果您可以控制插入和更新的顺序,则可以强制执行排列的唯一性:

alter table t23 
   add constraint tags_ck check (tag1 < tag2)
/
alter table t23 
   add constraint tags_uk unique (tag1, tag2)
/

这是有效的,因为检查约束拒绝('dog','cat')作为无效组合。因此,唯一约束可以确保只有evy一个记录具有标记的特定排列。

作为一种解决方案,这确实需要在插入和更新时进行一些干预,这可能足以为您提供此实现。我知道Oracle中使用基于函数的索引(我发布它here)的优雅解决方案,但我不认为MySQL支持类似的索引类型。