我的数据库包含一个用户表。每个活跃用户都有一个唯一的用户名。我希望能够停用用户并释放他们正在使用的用户名,但将它们保留在同一个表中。
有没有办法仅有条件地强制执行唯一性约束?
添加另一列,名为
isactive
。 然后在 (username, isactive)
上创建唯一约束。
然后您可以同时拥有活动和非活动用户名。 您将无法拥有两个活动用户名。
如果您想要多个非活动名称,请使用
NULL
作为 isactive
的值。 NULL
值可以在唯一索引中重复。
不,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'
布尔值时返回 user_deleted
常量来代替用户名列:
SELECT IF(u.user_deleted,'USER DELETED',u.username) AS username
(使用值 1 表示逻辑“用户已删除”条件。)
此方法的一大优点是无需修改
username
列、username
值和 UNIQUE 约束将防止插入具有重复用户名的新行。
不同的方法达到相同的结果。对于所提出的问题可能并不真正需要。但仅供参考。
如果您的情况很复杂,无法确定独特性,那么这是最适合的。还要考虑性能成本。
样品
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 ;
我只需创建另一个名为 FORMER_NAME 的(非唯一)字段,并在用户变为非活动状态时将原始名称移至该字段。不需要特殊的唯一性约束,这是不可能的。
不,如果有唯一索引(因此得名),则不能有重复项。添加额外的列以使每条记录都唯一。或者更改该值,使其唯一。
不推荐,但例如您可以添加时间戳“USER DELETED 2013/08/17:233805”
这是我遇到类似问题时的解决方案:
添加一列不活动的列,因此唯一键为:(用户名,不活动)
对于非活动,非活动 = 0 表示用户处于活动状态,非活动 > 0 表示用户处于活动状态
当停用用户时,只需设置inactive = user_id,而不是像我们通常那样设置1!
现在它允许非活动用户使用重复的用户名,但只允许活动用户使用唯一的用户名。
我通过添加提供可为空功能的生成列来扩展@gordon-linoff 答案。我宁愿有一个真正的非空活动列,它具有明确的真值和假值,我可以用它来读取和写入,这样不会造成混淆,并且以后在编写代码时不会因意外忘记此空行为而陷入混乱。因此,我计算一个具有专门名称的列,然后在约束中使用该值,这样我就得到了可为空的唯一活动行为,但可以根据需要使用活动列。
isactive BOOL NOT NULL,
_isactive_constraint_key_ BOOL AS (CASE WHEN isactive IS true THEN true END),
CONSTRAINT active_user UNIQUE(username, _isactive_constraint_key)