如果特定列具有特定值,SQL中是否有一种方法可以创建列必须唯一的约束?
示例:行并未真正删除,但在数据库中标记为“已删除”。在“未删除”行中,ValueA必须是唯一的:
ID ValueA ValueB Deleted
-----------------------------------------------------
1 'foo' 10 0
2 'bar' 20 0
3 'bar' 30 1
4 'bar' 40 1
5 'foo' 50 0 --NOT ALLOWED
我想到了类似CHECK约束的东西,但我不知道该怎么做。
答案 0 :(得分:4)
这是不可能的,可能是你可以使用触发器实现某些东西
答案 1 :(得分:1)
你能改变一下设计吗?
在我看来,你有一个“东西”列表。对于每个ValueA,任何时候都有一个活跃的“thingy”。这可以最好地建模如下:
从主Thingies表中删除ValueA并删除。
使用列ValueA和ID创建一个新表ActiveThingies。通过使ValueA成为唯一或主键来保护此表。 (您可能还需要使ID唯一,具体取决于单个ID是否可以代表超过1个ValueA)。
现在,使用ActiveThingies表来随时控制哪条记录是最新的。要更改“foo”的活动(未删除)记录,请在ActiveThingies中更新它的ID列。
要获取未删除项目列表,请加入两个表格。
但是,使用此设计,您将失去记住“已删除”“thingies”的ValueA的能力。如果您需要记住这些值,您还需要在Thingies中包含ValueA列。
答案 2 :(得分:0)
MySQL忽略了CHECK约束,因此您不能像在其他数据库中那样在MySQL中执行此操作。
这是一个黑客。对valueA +删除的唯一约束。删除行时不能只使用1,它们必须是1,2,3 ......
这至少可以让你在MySQL中实现服务器端,但是引入了一个步骤。标记要删除的行时,必须首先找到max(已删除),添加1,并在标记删除时插入该值。
答案 3 :(得分:0)
将表拆分为两个表:一个在ValueA上具有UNIQUE约束,另一个不在。使用视图+触发器组合两个表。类似的东西:
CREATE TABLE _Active (
ID INTEGER,
ValueA VARCHAR(255) UNIQUE,
ValueB INTEGER
);
CREATE TABLE _Deleted (
ID INTEGER,
ValueA VARCHAR(255), /* NOT unique! */
ValueB INTEGER
);
CREATE VIEW Thingies AS
SELECT ID, ValueA, ValueB, 0 AS Deleted FROM _Active
UNION ALL
SELECT ID, ValueA, ValueB, 1 AS Deleted FROM _Deleted;
CREATE TRIGGER _trg_ii_Thingies_Active
INSTEAD OF INSERT ON Thingies
FOR EACH ROW WHEN NOT NEW.Deleted
BEGIN
INSERT INTO _Active(ID, ValueA, ValueB)
VALUES (NEW.ID, NEW.ValueA, NEW.ValueB);
END;
CREATE TRIGGER _trg_ii_Thingies_Deleted
INSTEAD OF INSERT ON Thingies
FOR EACH ROW WHEN NEW.Deleted
BEGIN
INSERT INTO _Deleted(ID, ValueA, ValueB)
VALUES (NEW.ID, NEW.ValueA, NEW.ValueB);
END;
/* Add triggers for DELETE and UPDATE as appropriate */
(我不确定CREATE TRIGGER语法,但你知道我的意思。)
答案 4 :(得分:0)
此问题有解决方法 - 创建另一列 deleted_on
deleted_on timestamp NOT NULL DEFAULT '0000-00-00 00:00:00'
并在 ValueA 和 deleted_on 上制作唯一键。
UNIQUE KEY not_deleted (ValueA, deleted_on)
软删除记录插入NOW()
以获取deleted_on