简体   繁体   English

如何提供数据库约束以确保表中的此行为?

[英]How to give a database constraint to ensure this behavior in a table?

I have a table with five columns: A, B, C, D and E. 我有一个有五列的表:A,B,C,D和E.

And I need to comply with the following restrictions: 我需要遵守以下限制:

  • A is the primary key. A是主键。
  • For a B there can only be one C, ie: 1-1 ; 对于B,只能有一个C,即:1-1; 2-1 ; 2-1; 3-2 but not 1-2. 3-2但不是1-2。
  • BC and D can take any value but can not be repeated, ie: 1-1 1 ; BC和D可以取任何值,但不能重复,即:1-1 1; 1-1 2 ; 1-1 2; not 1-1 1 again. 再没有1-1 1。
  • E can take any value. E可以取任何价值。

So, considering the following order 所以,考虑以下顺序

| A | B | C | D | E |

| 1 | 1 | 1 | 1 | 1 | -> OK 

| 2 | 1 | 2 | 1 | 1 | -> Should fail, because there is a B with another C, 1-2 must be 1-1.

| 3 | 1 | 1 | 2 | 1 | -> OK

| 4 | 1 | 1 | 2 | 1 | -> Should fail, because relation between B-C and D is repeated.

| 5 | 2 | 1 | 1 | 1 | -> OK

Is there any way to comply with this behavior through some constraint in the database? 有没有办法通过数据库中的某些约束来遵守这种行为?

Thanks! 谢谢!

For B - C rule I would create a trigger 对于B - C规则,我会创建一个触发器

For the B - C - D rule looks like you want unique constraint 对于B - C - D规则看起来你想要唯一的约束

ALTER TABLE t ADD CONSTRAINT uni_BCD UNIQUE (B,C,D);

A and E are irrelevant to the question and can be ignored. A和E与问题无关,可以忽略。

The BCD rule can be easily solved by creating a unique index on BCD. 通过在BCD上创建唯一索引,可以轻松解决BCD规则。

If for every B there can be only one C then your DB is not normalized. 如果对于每个B只有一个C,那么您的DB不会被标准化。 Create a new table with B and C. Make B the primary key or create a unique index on B. Then remove C from the original table. 使用B和C创建一个新表。使B成为主键或在B上创建唯一索引。然后从原始表中删除C. (At which point the unique index on BCD becomes a unique index on BD.) (此时BCD上的唯一索引成为BD上的唯一索引。)

Without normalizing the tables, I don't think there's any way to do it with a constraint. 如果不对表进行规范化,我认为没有任何方法可以使用约束来实现。 You could certainly do it with a trigger or with code. 你当然可以使用触发器或代码来完成它。

This condition is not trivial 这种情况并非无足轻重

For a B there can only be one C, ie: 1-1 ; 对于B,只能有一个C,即:1-1; 2-1 ; 2-1; 3-2 but not 1-2. 3-2但不是1-2。

, since Oracle does not support CREATE ASSERTION (soon, we hope!) ,因为Oracle不支持CREATE ASSERTION (很快,我们希望!)

Therefore, you need to involve a second table to enforce this constraint, or else a statement-level AFTER INSERT/UPDATE trigger. 因此,您需要涉及第二个表来强制执行此约束,否则需要使用语句级别的AFTER INSERT / UPDATE触发器。

What I would do is create a second table and have it maintained via an INSTEAD OF trigger on a view, and ensure all my application DML happened via the view. 我要做的是创建第二个表并通过视图上的INSTEAD OF触发器进行维护,并确保通过视图发生我的所有应用程序DML。 (You could also just create a regular trigger on the table and have it maintain the second table. That's just not my preference. I find INSTEAD OF triggers to be more flexible and more visible.) (你也可以在桌子上创建一个常规触发器并让它维护第二个表。这不是我的偏好。我发现INSTEAD OF触发器更灵活,更可见。)

In case it's not clear, the purpose of the second table is that it allows you to enforce your constraint as a FOREIGN KEY constraint. 如果不清楚,第二个表的目的是它允许您将约束强制执行为FOREIGN KEY约束。 The UNIQUE or PRIMARY KEY constraint on the second table ensures that each value of B appears only once. 第二个表上的UNIQUEPRIMARY KEY约束确保B每个值仅出现一次。

Here's sample code for that approach: 以下是该方法的示例代码:

--DROP TABLE table1_parent;
--DROP TABLE table1;


CREATE TABLE table1_parent
 ( b number NOT NULL,
   c number NOT NULL,
   constraint table1_parent_pk PRIMARY KEY (b),
   constraint table1_parent_u1 UNIQUE (b, c) );

CREATE TABLE table1
(
  a   NUMBER NOT NULL,
  b   NUMBER NOT NULL,
  c   NUMBER NOT NULL,
  d   NUMBER NOT NULL,
  e   NUMBER NOT NULL,
  CONSTRAINT table1_pk PRIMARY KEY (a),  -- "A is the primary key."
  CONSTRAINT table1_fk FOREIGN KEY ( b, c ) REFERENCES table1_parent ( b, c ), -- "For a B there can only be one C, ie: 1-1 ; 2-1 ; 3-2 but not 1-2."
  CONSTRAINT table1_u2 UNIQUE ( b, c, d ) -- "B-C and D can take any value bue can not be repeated, ie: 1-1 1 ; 1-1 2 ; not 1-1 1 again."
);

CREATE INDEX table1_n1 ON table1 (b,c); -- Always index foreign keys

CREATE OR REPLACE VIEW table1_dml_v AS SELECT * FROM table1;

CREATE OR REPLACE TRIGGER table1_dml_v_trg INSTEAD OF INSERT OR UPDATE OR DELETE ON table1_dml_v
DECLARE
  l_cnt NUMBER;
BEGIN
  IF INSERTING THEN
    BEGIN
      INSERT INTO table1_parent (b, c) VALUES ( :new.b, :new.c );
    EXCEPTION
      WHEN dup_val_on_index THEN
        NULL;  -- parent already exists, no problem
    END;

    INSERT INTO table1 ( a, b, c, d, e ) VALUES ( :new.a, :new.b, :new.c, :new.d, :new.e );
  END IF;

  IF DELETING THEN
    DELETE FROM table1 WHERE a = :old.a;

    SELECT COUNT(*) INTO l_cnt FROM table1 WHERE b = :old.b AND c = :old.c;

    IF l_cnt = 0 THEN
      DELETE FROM table1_parent WHERE b = :old.b AND c = :old.c;
    END IF;
  END IF;

  IF UPDATING THEN
    BEGIN
      INSERT INTO table1_parent (b, c) VALUES ( :new.b, :new.c );
    EXCEPTION
      WHEN dup_val_on_index THEN
        NULL;  -- parent already exists, no problem
    END;

    UPDATE table1 SET a = :new.a, b = :new.b, c = :new.c, d = :new.d, e = :new.d WHERE a = :old.a;

    SELECT COUNT(*) INTO l_cnt FROM table1 WHERE b = :old.b AND c = :old.c;

    IF l_cnt = 0 THEN
      DELETE FROM table1_parent WHERE b = :old.b AND c = :old.c;
    END IF;

  END IF;      
END;


insert into table1_dml_v ( a,b,c,d,e) VALUES (1,1,1,1,1);
insert into table1_dml_v ( a,b,c,d,e) VALUES (2,1,2,1,1);
insert into table1_dml_v ( a,b,c,d,e) VALUES (3,1,1,2,1);
insert into table1_dml_v ( a,b,c,d,e) VALUES (4,1,1,2,1);
insert into table1_dml_v ( a,b,c,d,e) VALUES (5,2,1,1,1);

If your system supports fast refreshed materialized views, please try the following. 如果您的系统支持快速刷新的物化视图,请尝试以下操作。
Since I currently don't access to a this feature, I can't verify the solution. 由于我目前无法访问此功能,因此无法验证解决方案。

create materialized view log on t with primary key;

create materialized view t_mv
refresh fast
as
select      b,c
from        t
group by    b,c
;

alter table t_mv add constraint t_mv_uq_b unique (b);

and off course: 当然:

alter table t add constraint t_uq_a_b_c unique (b,c,d);

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

相关问题 如何在表上放置约束以确保表的子集中只有一个布尔列为真? - How do I put a constraint on a table to ensure only one boolean column across a subset of tables is true? 是否有SQL表约束来确保两列之间存在关系? - Is there a SQL table constraint to ensure that a relationship exists between two columns? 如果我不知道表是否存在,如何确保不存在外键约束? - How can I ensure a foreign key constraint doesn't exist, if I don't know whether the table exists? 如何确保计数表的连续性? - How to ensure contiguity of a tally table? 如何为Oracle中的列组合提供唯一约束? - How to give a unique constraint to a combination of columns in Oracle? 我们如何使用约束来确保数组的所有值都不是 NULL? - How can we use a constraint to ensure that no values of an array are NULL? 设置事务隔离级别的范围,如何确保它只在当前表或数据库上设置 - SCOPE OF SET TRANSACTION ISOLATION LEVEL, How ensure it only set on current table or Database 删除一个 SQL Table Column give Constraint dependency error - Delete a SQL Table Column give Constraint dependency error SQL-约束以确保一个表中的值绑定到另一表中的适当值 - SQL - Constraint to ensure value in one table is tied to the appropriate value in another table H2数据库CREATE TABLE有约束 - H2 database CREATE TABLE with constraint
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM