【问题标题】:Oracle Constraint with three columns, but only one row can equal a certain value具有三列的 Oracle 约束,但只有一行可以等于某个值
【发布时间】:2021-05-01 22:54:34
【问题描述】:

这听起来很简单,也可能很简单。我有 3 列,一列带有常量字符串(名称),一列(状态)带有两个选项(外键),另一列(room_id)是另一个表的父键,如何确保只设置一行为同名的“ON”值。不能有多个具有相同名称的“ON”值的行,但可以有多个具有相同名称的“OFF”值的行。示例。

room_id       name       status
1             daniel       ON   --- OK for only one ON to be set for daniel
2             daniel       OFF
3             daniel       OFF
4             daniel       OFF
5             daniel       OFF
6             daniel       ON  --- THIS IS NOT ALLOWED...  but everything is UNIQUE
1             jeff         OFF
2             jeff         OFF
3             jeff         ON  --- OK for only ONE to be set to "ON" for jeff.
4             jeff         ON  --- THIS IS NOT ALLOWED... the room_id keeps things UNIQUE
5             jeff         ON  --- THIS IS NOT ALLOWED...

下面的 UNIQUE 约束允许多个同名的“ON”值。

ADD CONSTRAINT constratin_name_uq UNIQUE (room_id, name, status)

我相信我也需要一个 CHECK 约束,但在 value = 'ON'... 的状态列上的 COUNT 不大于 1...以确保只有一个“NAME”和“STATUS”具有 ON 值....

下面的约束不允许多个“OFF”值,这在我的情况下是必需的。

ADD CONSTRAINT constraint_name_uq UNIQUE (name, status)

另外...一切都可以“关闭”,但每个给定名称只能有一个“开启”。

感谢您的帮助,

谢谢你, 丹尼尔

【问题讨论】:

  • 您可能需要使用前触发器

标签: oracle constraints unique multiple-columns


【解决方案1】:

您可以创建唯一索引:

CREATE UNIQUE INDEX table_name__status_name__u
  ON table_name( CASE status WHEN 'ON' THEN name END );

其中,对于表格:

CREATE TABLE table_name (
  room_id NUMBER
          NOT NULL,
  name    VARCHAR2(10)
          NOT NULL,
  status  VARCHAR2(3)
          NOT NULL
          CHECK ( STATUS IN ( 'ON', 'OFF' ) )
);

然后这个工作:

INSERT INTO table_name ( room_id, name, status )
SELECT 1, 'alice', 'ON' FROM DUAL UNION ALL
SELECT 2, 'alice', 'OFF' FROM DUAL UNION ALL
SELECT 3, 'alice', 'OFF' FROM DUAL UNION ALL
SELECT 4, 'alice', 'OFF' FROM DUAL UNION ALL
SELECT 5, 'alice', 'OFF' FROM DUAL UNION ALL
SELECT 6, 'alice', 'OFF' FROM DUAL UNION ALL
SELECT 1, 'beatrice', 'OFF' FROM DUAL UNION ALL
SELECT 2, 'beatrice', 'OFF' FROM DUAL UNION ALL
SELECT 3, 'beatrice', 'OFF' FROM DUAL;

但是,这个:

INSERT INTO table_name ( room_id, name, status )
SELECT 7, 'alice', 'ON' FROM DUAL;

失败:

ORA-00001: unique constraint (FIDDLE_XFKAWDIVOXGJZVQESSZQ.TABLE_NAME__STATUS_NAME__U) violated

这也失败了,同样的例外:

INSERT INTO table_name ( room_id, name, status )
SELECT 4, 'beatrice', 'ON' FROM DUAL UNION ALL
SELECT 5, 'beatrice', 'ON' FROM DUAL;

db小提琴here

【讨论】:

  • room_id 来自的表已经有检查约束,因此值只有“ON”或“OFF”。那么仅 UNIQUE 索引就可以解决问题吗?
  • 对所有更新/删除的 cmets 感到抱歉...经过进一步测试,它正在工作。谢谢。
【解决方案2】:

您的数据库中有冗余数据。一旦一个房间为给定名称打开,所有其他房间都知道(根据您的业务规则)对该名称关闭,并且不应将其存储在数据库中。只要有一个“person_location”表,有两列,name 和 current (ON) room_id number。对于那些人不在任何地方的时候,他的 room_id 应该设置为 NULL。假设此人一次不能在多个地方(同样,这似乎是您的业务规则),您可以通过将其当前位置作为已经存在的主人员表中的附加列来使事情变得更加简单,让您不必首先创建这个额外的表。

【讨论】:

    猜你喜欢
    • 2021-09-30
    • 2015-07-17
    • 2010-09-15
    • 1970-01-01
    • 1970-01-01
    • 2020-07-26
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多