在 INSERT 语句期间使用 CHECK 约束来验证数据是一种好习惯吗

Is it a good practice to use CHECK constraints to validate data during an INSERT statement

在将数据插入 table、使用 CHECK 约束或使用 if 语句之前,哪种方法被认为可以更好地验证数据输入?有没有更好的验证方法?

1)

DECLARE
 INVALID_DATE EXCEPTION;
...
-- Check if date is valid
IF TO_DATE(dt,'DD/MM/YYYY') > TO_DATE('10/10/2010','DD/MM/YYYY')THEN
 RAISE INVALID_DATE;
END IF;

-- Insert data only if it is valid
INSERT INTO Table VALUES(dt);

EXCEPTION
 WHEN INVALID_DATE
      THEN DBMS_OUTPUT.PUT_LINE('Date is not valid');
...

2)

...
-- Do NOT check if date is valid and let an 
-- CHECK constraint exception(CH_TABLE1) be raised if it is invalid
INSERT INTO Table VALUES(dt);

EXCEPTION
 WHEN CHECK_CONSTRAINT_VIOLATED THEN
   IF SQLERRM LIKE 'ORA-02290:%CH_TABLE1%' THEN
       DBMS_OUTPUT.PUT_LINE('Date is not valid');
   ...
   END IF;
...

如果 updates/inserts 可以来自多个 applications/scripts,尤其是临时查询,那么检查约束将所需的业务逻辑放在一个地方,这是一件好事。

如果 updates/inserts 来自一个 application/source,最好在应用程序中进行检查(在本例中为存储过程)。

检查约束是一个包罗万象的东西,但它有点隐藏。

这取决于 - 通常需要多层方法。

例如,您可能有一组简单的业务规则,可以作为检查约束直接在数据库中维护。我只将它们用于简单、独立的检查。

示例 - 检查 Y/N 标志:

alter table example_table add constraint ck_example_table_flag
check (flag is null or flag in ('Y', 'N');

在这种情况下,如果您在此列中获得任何其他值,您就知道数据有误,而且这条规则不会随着时间的推移而改变。添加此约束将防止任何应用程序破坏您的数据。

对于可能不是独立的更复杂的业务规则,例如,如果日期取决于输入值的人或另一个 table 中另一个字段的内容,那么我会处理这个在 'application'.

有时 'application' 数据库 - 在这种情况下,您的检查约束可能在 table 触发器中或打包 pl/sql 处理所有 table 更新。例如:

example_app.update_data(id => 1000, value => 'foo');

如果这是处理数据更新的方式,那么将业务规则处理为检查约束、带检查的触发器或直接在 update_data 过程中处理都没有错。

在许多企业环境中,应用层和数据库层将由不同的团队处理。如果您在支持应用程序层的团队中,您可能会发现向数据库团队提出更改请求以放置检查约束太痛苦了——在这种情况下,向应用程序层添加一些逻辑会让人感觉更糟直截了当。相反,数据库团队可能会发现它更直接。

@Bohemian 关于在有多个客户端时使用检查约束来强制执行数据完整性。

支持使用检查约束的另一个考虑因素是,它们可以通过允许优化器推断某些值不能出现在 table 中来提高性能。

在存在限制日期列的约束的情况下检查:

my_col > 日期 '2010-01-01'

... 带有谓词的查询,例如:

my_col = 日期 '2009-01-01'

... 可以确定不会从 table.

返回任何行