PL/SQL 中的验证检查

Posted

技术标签:

【中文标题】PL/SQL 中的验证检查【英文标题】:Validation checks in PL/SQL 【发布时间】:2021-12-30 00:23:23 【问题描述】:

根据我的项目要求,我需要将所有验证检查查询存储在一个表中,并验证另一个表的所有记录,并使用其验证状态更新每条记录。 例如,我有两个表名为 EMPVALIDATIONS

验证表有如下两列:

-------------------    --------------
Validation_desc        Validation_sql
------------------     --------------
EID_IS_NULL            related SQL should be here
SAL_HIGH               related SQL should be here

EMPtable 有像eid,ename,sal,dept,is_valid,val_desc 这样的普通列。

我应该编写 PL/SQL 代码,该代码将从 VALIDATIONS 表中获取所有验证 sql,并检查 EMP 表的每条记录并验证它们。如果第一条记录通过VALIDATIONS 表中可用的所有验证成功,则EMPIS_VALID 列应更新为1,Validation_desc 对于该特定记录应为空。如果第二条记录通过 2 次检查失败,则该记录的 IS_VALID 列应更新为 0,Validation_desc 应更新为 Validation_desc 并以逗号分隔,同样,它应该检查 EMP 的所有记录的所有验证表。

我已尝试使用以下代码从两个表中获取所有详细信息,但无法编写验证逻辑。

CREATE  PROCEDURE P_VALIDATION
as
    TYPE REC_TYPE IS  RECORD( Validation_desc     VARCHAR2(4000),
                              Validation_sql      VARCHAR2(4000));

    TYPE VAL_CHECK_TYPE IS TABLE OF REC_TYPE;

    LV_VAL_CHECK     VAL_CHECK_TYPE;

    CURSOR CUR_FEED_DATA IS SELECT * FROM EMP;

    LV_FEED_DATA    EMP%ROWTYPE;
BEGIN

    SELECT Validation_desc, Validation_sql
    BULK COLLECT INTO LV_VAL_CHECK FROM VALIDATIONS;

    OPEN CUR_FEED_DATA;
    LOOP
        FETCH CUR_FEED_DATA INTO LV_FEED_DATA;

        EXIT WHEN CUR_FEED_DATA%NOTFOUND;

        FOR I IN LV_VAL_CHECK.FIRST .. LV_VAL_CHECK.LAST LOOP
            ----SOME VALIDATIONS LOGIC HERE--
        END LOOP;

    END LOOP;

    CLOSE CUR_FEED_DATA;

END;

【问题讨论】:

【参考方案1】:

没有单一类型的验证。验证可以是 null、不为 null、是真/假、返回行/无行等。有几种方法可以解决这个问题

编写您自己的断言包,其中包含用于每种验证类型的过程。在您的表中,您将存储验证类型和要评估的表达式。这是一项相当多的工作。 利用 utPLSQL 之类的开源测试框架并对其进行一些修改以满足您的需求。所有类型的验证都已经在那里实施。如果您决定走这条路,请注意版本 2 和 3 之间存在重大差异

【讨论】:

【参考方案2】:

首先要注意@KoenLostrie 的开场白:没有单一类型的验证。 这基本上是说没有单一的过程可以解决问题。但是使用数据库的内置验证应该是您的第一道攻击线。使用简单的预定义约束,这两个示例验证都不再是必需的:

使用约束来定义……——一个规则 限制数据库中的值。 Oracle 数据库允许您创建 六种类型的约束...

对于您概述的表格,约束可以处理您概述的验证和一些附加功能:

+-------------+--------+----------------------------------+-----------------------------------------------------+
| Validation  | Column | Constraint Type                  | Description                                         |
+-------------+--------+----------------------------------+-----------------------------------------------------+
| Eid_is_Null | eid    | Primary Key                      | Guarantees eid is not null and is unique in table   |
+-------------+--------+----------------------------------+-----------------------------------------------------+
| Sal_High    | salary | Check (salary <= 50000)          | Guarantees salary column is not greater than 50,000 |
+-------------+--------+----------------------------------+-----------------------------------------------------+
| Dept_OK     | dept   | not null                         | Ensures column is present                           |
+                      +----------------------------------+-----------------------------------------------------+
|             |        | Foreign key to Departments table | Guarantees value exists in reference table          |
+-------------+--------+----------------------------------+-----------------------------------------------------+
| Name_Ok     | ename  | not null                         | Ensures column is present                           |
+-------------+--------+----------------------------------+-----------------------------------------------------+

对于上面列出的以及添加的任何其他约束,您不需要需要查询来验证 - 数据库管理器根本不允许存在无效行。当然,现在您的代码需要处理产生的异常。 不幸的是,约束不能处理每个验证,因此您仍然需要验证例程来记录这些。但是,您不应该创建一个逗号分隔的列表(它们不仅违反了第一范式,而且它们总是比它们的价值更麻烦 - 当错误解决后如何更新列表?)而是创建一个新表 - @987654323 @如:

create table emp_violations ( 
             emp_vio_id       integer generated always as identity
           , emp_id           integer              -- or type of emp_id
           , vol_id           integer              -- or type of vio_id (the pk of violations table)
           , date_created     date
           , date_resolved    date
           , constraint       emp_violations_pk
                              primary key (emp_violation_id)
           , constraint       emp_violations_2_emp_fk
                              foreign key (emp_id)
                              references emp(mp_id)
           , constraint       emp_violations_2_violations_fk
                              foreign key (vio_id)
                              references violations(vio_id)                              
           ); 

通过此功能,您可以轻松查看已经存在或当前存在哪些非约束违规行为,以及解决它们的时间。同时删除列Validation_desc(不再需要)和is_valid(可从未解决的emp_violations 导出,无需额外的列维护)。 如果您绝对必须获取 is_valid 和逗号分隔的违规列表,则使用 LISTAGG 函数创建一个视图。

【讨论】:

以上是关于PL/SQL 中的验证检查的主要内容,如果未能解决你的问题,请参考以下文章

从 PL/SQL 中的过程返回值数组

如何验证作为参数 PL/SQL 给出的 YYYYMMDD 日期

检查 PL/SQL 异常块中的特定错误代码

在 PL/SQL 中验证 IBAN

PL/SQL:检查触发器中的所有行后运行包

如何检查 Oracle PL/SQL 中的参数列表值?