如何仅在表行的子集内保证表值的唯一性?

时间:2011-10-01 06:11:17

标签: php mysql

我有一个属于不同用户的项目表:

project_id,owner_user_id,project_name

我不需要project_names对表是全局唯一的,因此使project_name UNIQUE没有帮助。我想阻止用户在INSERT或UPDATE上创建重复的project_names。

在INSERT / UPDATE时,我只想检查是否已经存在属于特定owner_user_id的project_name,如果它已经存在,则INSERT / UPDATE应该失败。

我可以使用SELECT首先在用户的项目中检查project_name是否存在,然后如果select没有返回结果,则只执行INSERT / UPDATE。但这是多线程的,另一个线程可以在执行SELECT之后但在INSERT / UPDATE之前立即插入相同的project_name。将这一切都纳入交易感觉就像是矫枉过正。是否有单个查询可以执行此操作?

5 个答案:

答案 0 :(得分:1)

您可以在两列中添加UNIQUE constraint作为一对:

alter table your_table add unique (owner_user_id, project_name)

这将确保project_name值对每个用户而言是唯一的。您需要查看collation set up以确保比较project_name值,而不考虑大小写。或者,您可以在访问数据库之前将项目名称标准化为标题大小写。

除非必须,否则不要尝试手工维护数据完整性,让数据库尽可能地处理您的约束。

答案 1 :(得分:0)

这确实需要在交易中。您需要检索一些信息(“哪些名称已被使用?”)然后对其进行操作(“如果我的名字未被使用,则使用它”)。这必须以原子方式完成。

正如你所推测的那样,如果在检查后插入没有原子地发生,就会出现竞争条件。

这是交易的目的。

答案 2 :(得分:0)

您可以在两个字段上添加唯一约束

 CONSTRAINT C_UNICITY UNIQUE (owner_user_id, project_name)

每次尝试插入或更新存在重复的记录时,都会出现sql错误

答案 3 :(得分:0)

$result = mysql_query("select * from Project where owner_user_id='1';");         
if (mysql_affected_rows()==0) {
    $result = mysql_query("insert into Project (projectname) values ('pojectname');");

答案 4 :(得分:0)

根据数据库参照完整性违规,为您提供陷阱错误通常不是UI验证的首选形式 - 您通常需要更高抽象级别的东西。但是,对于使用事务和UNIQUE约束来保护您的数据和用户一样,没有什么特别“过分”。