我的数据库包含一个用户表。每个活跃用户都有唯一的用户名。我希望能够停用用户并释放他们正在使用的用户名,但请将它们保存在同一个表中。
有没有办法只有条件地强制执行唯一性约束?
答案 0 :(得分:43)
添加另一个名为isactive
的列。在(username, isactive)
上创建一个唯一约束。
然后,您可以同时拥有活动和非活动用户名。您将无法拥有两个活动用户名。
如果您想要多个非活动名称,请使用NULL
作为isactive
的值。 NULL
值可以在唯一索引中重复。
答案 1 :(得分:8)
不,UNIQUE约束不能是“有条件的”。
一个选项是将username
列设置为NULL。 UNIQUE约束将允许多行具有NULL值。
您可以将其翻译为您想要显示的任何字符串。在应用程序中,或在SQL
中SELECT IFNULL(t.username,'USER DELETED') AS username
FROM mytable t
如果要保留这些行以用于历史/存档目的,您可能不希望更新username
列。 (如果更改username
列的值,则允许后续语句插入与先前用户名具有相同值的行。)
您可以在表中添加一个附加列,以表示“用户已删除”条件。例如:
user_deleted TINYINT(1) UNSIGNED DEFAULT 0 COMMENT 'boolean'
只要设置了'USER DELETED'
boolean,您就可以检查此列并返回user_deleted
常量来代替username列:
SELECT IF(u.user_deleted,'USER DELETED',u.username) AS username
(使用值1表示逻辑“用户删除”条件。)
此方法的一大优势是不必修改username
列,username
值和UNIQUE约束将阻止插入具有重复用户名的新行。
答案 2 :(得分:3)
实现相同结果的不同方式。问题可能不是真正的要求。但仅供参考。
如果您的条件很复杂,决定唯一性,这是最合适的。还要考虑性能成本。
<强>示例强>
DELIMITER $$
CREATE TRIGGER `my_trigger` BEFORE INSERT/UPDATE
ON `usertable`
FOR EACH ROW BEGIN
IF EXISTS (SELECT 1 FROM usertable WHERE userid <> NEW.userid AND username = NEW.username AND isactive = 1) THEN
SELECT CONCAT(NEW.username, ' exists !') INTO @error_text;
SIGNAL SQLSTATE '45000' SET message_text = @error_text;
END IF;
END$$
DELIMITER ;
答案 3 :(得分:0)
不,如果有唯一索引(因此名称),则不能有重复项。添加一个额外的列以使每个记录唯一。或者更改值以使其独特。
不推荐,但例如您可以添加时间戳“USER DELETED 2013/08/17:233805”
答案 4 :(得分:0)
我会创建另一个名为 FORMER_NAME 的(非唯一)字段,并在用户处于非活动状态时将原始名称移至该字段。不需要不可能的特殊唯一性约束。