如何约束数据库表,使一列中只有一行可以具有特定值?

Posted

技术标签:

【中文标题】如何约束数据库表,使一列中只有一行可以具有特定值?【英文标题】:How to constrain a database table so only one row can have a particular value in a column? 【发布时间】:2010-09-15 23:39:04 【问题描述】:

使用 Oracle,如果列值可以是“YES”或“NO”,是否可以约束表,以便只有一行可以具有“YES”值?

我宁愿重新设计表结构,但这是不可能的。

[UDPATE] 遗憾的是,此表中不允许使用空值。

【问题讨论】:

哦,亲爱的 - 不允许使用空值 - 这会稍微改变一些 - 现在您必须使用基于函数的索引 (@Tony Andrews)。仍然避免触发和自主事务。 【参考方案1】:

它不适用于表定义。

但是,如果您使用调用存储过程的触发器更新表,则可以确保只有一行包含“YES”。

    将所有行设置为“否” 将你想要的行设置为YES

【讨论】:

-1 用于基于触发器的解决方案。它们在强制执行表级约束方面效果不佳【参考方案2】:

这是一个笨拙的 hack,但如果该列允许 NULL,那么您可以使用 NULL 代替“NO”并像以前一样使用“YES”。将唯一键约束应用于该列,您将永远不会得到两个“YES”值,但仍然有很多 NO。

更新:@Nick Pierpoint:建议添加检查约束,以便将列值限制为“YES”和 NULL。语法都在他的回答中制定出来。

【讨论】:

没有什么笨拙的 - 这就是要走的路。 +1 您还需要在表上添加一个检查约束,这样它就不允许除“YES”或 null 之外的任何内容。 如果你想让它看起来不错,你也可以用 NVL 包裹一个视图,然后你会得到你的 Y/N 好吧,如果你想加入它,使用 NULL 是很麻烦的。这可能是一个值得做的事情,但它仍然是一个设计妥协,远离更正确的方法。【参考方案3】:

Oracle 是否支持类似过滤索引(上周我听说例如 MSSQL2008 支持)?也许您可以定义一个唯一键,它仅适用于列中值为“Yes”的行。

【讨论】:

没有过滤索引,但 FBI 提供了一种更灵活(如果可以说不太简洁)的方式来做同样的事情。【参考方案4】:

使用基于函数的索引:

create unique index only_one_yes on mytable
(case when col='YES' then 'YES' end);

Oracle 只索引不完全为空的键,这里的 CASE 表达式确保所有 'NO' 值都更改为空值,因此不被索引。

【讨论】:

【参考方案5】:

我想我会使用第二个表来指向您当前表中的相应行。另一个表也可以用来存储其他变量的值。

【讨论】:

难以在一致的环境中维护【参考方案6】:

根据我对 yukondude 之前的回答的评论,我将添加一个唯一索引和一个检查约束:

create table mytest (
    yesorno varchar2(3 char)
);

create unique index uk_mytest_yesorno on mytest(yesorno);

alter table mytest add constraint ck_mytest_yesorno check (yesorno is null or yesorno = 'YES');

【讨论】:

我认为只要 NULL 适合作为“不是”值,此方法就比 FBI 方法具有优势,因为优化器至少可以利用约束。我认为以 yesorno='YES' 和 yesorno 为空的谓词查询将获得更好的基数估计。 由于只有 1 行带有“YES”并且每隔一行带有 null,那么您将获得用于查找“YES”行和完整扫描的索引(非常正确)得到其他一切(“不”)。 当然——这只是一个问题,用 Null 替换“否”是否是实现这一目标的一个值得妥协的方案。【参考方案7】:

您将需要查看 Tom Kyte 的文章,其中确切地提出了这个问题及其答案:

http://tkyte.blogspot.com/2008/05/another-of-day.html

总结:不要使用触发器,不要使用自治事务,使用两个表。

如果您使用 Oracle 数据库,那么您必须了解 AskTom 并获取他的书籍。

【讨论】:

所提出的问题与此略有不同,在汤姆的问题中,表格可以有多个“Y”,但每个国家/地区只有 1 个。当我读到它时,在这个例子中,表只能有 1 是,在这种情况下索引解决方案似乎有效。但是,是的,AskTom 是 Oracle 数据库的必备工具。 我同意。如果汤姆被问到这个问题,我猜他肯定会选择索引解决方案。

以上是关于如何约束数据库表,使一列中只有一行可以具有特定值?的主要内容,如果未能解决你的问题,请参考以下文章

sql中如何使一列中的多个重复数据只显示一次, 求大神指导,使得图中的班简名重复的只显示一次。

约束 CONSTRAINT

从表中选择行,其中具有相同 id 的另一个表中的行在另一列中具有特定值

sql中如何使一列中的多个重复数据只显示第一条

Sql Server 主键 外键约束

如何在表的每一行中查找哪一列包含特定值