对于字段的特定值,表的唯一约束

时间:2017-11-25 08:06:52

标签: mysql sql mariadb unique-key

我有发票表。它有很多领域,但问题是2个主要领域

  • InvoiceNo - 字母数字值
  • 已删除 - 布尔值1或0,表示记录是否已删除。

我们的业务要求InvoiceNo是独一无二的。但是,如果删除了一行,我们可以重新使用InvoiceNo

InvoiceNo    Deleted
123Er        1
123Er        0

以上是有效的用例。但我不想再与123Er& 0

是否可以为特定值的2个字段组合创建唯一键唯一(InvoiceNo,Deleted = 0)还是应该用于存储过程还是触发器?

3 个答案:

答案 0 :(得分:2)

function based index的帮助下,很容易在其他RDBMS系统中实现

至于现在MySql没有这样的功能,但从版本5.7开始,可以使用虚拟(或生成)列进行模拟。
简单的工作示例:http://rextester.com/HGY68688

CREATE TABLE IF NOT EXISTS mytable1234(
  InvoiceNo varchar(10),
  Deleted int,
  xxx varchar(10) generated always as (case when deleted = 0 then InvoiceNo end) virtual
);

create unique index myindex12 on mytable1234( xxx );

INSERT INTO mytable1234( InvoiceNo, Deleted)  VALUES ('aaa1', 0 );
INSERT INTO mytable1234( InvoiceNo, Deleted)  VALUES ('aaa1', 1 );
INSERT INTO mytable1234( InvoiceNo, Deleted)  VALUES ('aaa1', 1 );

-- INSERT INTO mytable1234( InvoiceNo, Deleted)  VALUES ('aaa1', 0 );

如果您取消注释此代码段中的最后一个INSERT,然后尝试运行此代码段,则会出现Duplicate entry 'aaa1' for key 'myindex12'错误。
通过这种方式,表中可能有多条记录InvoiceNo的{​​{1}}值相同,但deleted = 1只有一个值,因为MySql不允许这样做。

答案 1 :(得分:2)

您可以将字段重命名为DeletedIfNull(或IsActive)。

然后,该字段将取值" 1"或"真"或者无论列是否有效。对于任何其他值,它将是NULL。然后你可以创建:

create unique index unq_t_invoiceno_isactive on t(invoiceno, isactive);

MySQL(尽管不是所有数据库)在定义唯一索引时允许重复。因此,这将解决您当前的问题。

答案 2 :(得分:0)

你可以创建一个唯一的密钥(InvoiceNo,Deleted),并完成它。我不明白为什么你需要制作(InvoiceNo,Deleted = 0),这是不受支持的。拥有这两列的唯一键可以满足您的需求。

更新: 我遇到了你的问题,你可能有两个相同值的删除行。在这种情况下,我建议您将某些添加到已删除值的InvoiceNo列中,以便它们不会是唯一的。

例如: 您有 123er 然后删除它,因此它变为 123er-1 。当您删除另一个时,它将变为 123er-2 。你甚至可以在更新(之前)触发器中完成它。