我可以有条件地强制执行唯一性约束吗?

问题描述 投票:0回答:7

我的数据库包含一个用户表。每个活跃用户都有一个唯一的用户名。我希望能够停用用户并释放他们正在使用的用户名,但将它们保留在同一个表中。

有没有办法仅有条件地强制执行唯一性约束?

mysql unique-constraint
7个回答
73
投票

添加另一列,名为

isactive
。 然后在
(username, isactive)
上创建唯一约束。

然后您可以同时拥有活动和非活动用户名。 您将无法拥有两个活动用户名。

如果您想要多个非活动名称,请使用

NULL
作为
isactive
的值。
NULL
值可以在唯一索引中重复。


10
投票

不,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 约束将防止插入具有重复用户名的新行。


2
投票

不同的方法达到相同的结果。对于所提出的问题可能并不真正需要。但仅供参考。

  1. 在插入/更新时创建触发器
  2. 检查当前(新)记录值是否存在重复记录。
    a.这可以通过计算重复项或检查是否存在具有相同值但主键不同的其他记录来检查
  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 ;

1
投票

我只需创建另一个名为 FORMER_NAME 的(非唯一)字段,并在用户变为非活动状态时将原始名称移至该字段。不需要特殊的唯一性约束,这是不可能的。


0
投票

不,如果有唯一索引(因此得名),则不能有重复项。添加额外的列以使每条记录都唯一。或者更改该值,使其唯一。

不推荐,但例如您可以添加时间戳“USER DELETED 2013/08/17:233805”


0
投票

这是我遇到类似问题时的解决方案:

添加一列不活动的列,因此唯一键为:(用户名,不活动)

对于非活动,非活动 = 0 表示用户处于活动状态,非活动 > 0 表示用户处于活动状态

当停用用户时,只需设置inactive = user_id,而不是像我们通常那样设置1!

现在它允许非活动用户使用重复的用户名,但只允许活动用户使用唯一的用户名。


0
投票

我通过添加提供可为空功能的生成列来扩展@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)
© www.soinside.com 2019 - 2024. All rights reserved.