sql:如何通过存储过程完成数据验证?

时间:2011-04-18 05:38:42

标签: sql oracle

  

“存储过程通常用于数据验证或   封装结合多个SQL查询的大型复杂处理指令。“

说这个Oracle reference。那么有人可以通过在现实世界中举例说明存储过程如何用于数据验证来帮助我理解吗?

3 个答案:

答案 0 :(得分:4)

验证可能意味着很多事情,并且可以通过各种方式在数据库中完成:

  • 列数据类型本身就是一种验证形式:NUMBER列仅接受有效数字等
  • 主键,唯一和外键约束执行验证
  • 检查约束执行其他简单的单行验证,例如:
    • END_DATE> START_DATE
    • SALARY> 0
    • JOB = SALESMAN或COMMISSION为空

但是,上述任何一项都无法执行更复杂的验证规则,例如:   - SALARY< =(SELECT max_sal FROM config_table)   - emp.start_date BETWEEN他们被分配到的部门的start_date和end_date

有多种方法可以强制执行这些规则,包括数据库触发器,但通常首选的方法是创建一个存储过程,通常称为“API”来执行验证和操作,例如。

PROCEDURE insert_emp (...) IS
    ...
BEGIN
    -- Validate
    -- 1) Salary less than max
    SELECT max_sal
    INTO   l_max_sal
    FROM   config;
    IF p_sal > l_max_sal THEN
        error_pkg.raise_error ('Salary is too high');
    END IF;
    ...
    -- Insert
    INSERT INTO emp (...) VALUES (...);
END; 

然后,应用程序可以直接调用此过程,而不是直接执行更新,并且将执行所有必要的验证。事实上,应用程序可能来调用此过程 - 可能会禁用直接插入表中。

答案 1 :(得分:3)

发生数据验证是因为要将数据传递到存储过程,它是通过显式设置为Oracle数据类型的参数(或用户定义的类型,也基于Oracle数据类型)完成的。仅发生数据类型的验证 - 必要时必须构建更深入的验证(IE:检查NUMBER数据类型中的小数)。参数化查询通常比SQL注入更安全,但它实际上取决于参数是什么以及查询正在做什么。

 CREATE OR REPLACE PROCEDURE example (IN_VALUE NUMBER) IS

 BEGIN

   SELECT t.*
     FROM TABLE t
    WHERE t.column = IN_VALUE;

 END;

在此示例中,提交VARCHAR /字符串将导致错误 - 除NUMBER支持之外的任何内容都将导致错误。如果无法将IN_VALUE数据类型隐式转换为TABLE.column的数据类型,则会出现错误。

存储过程封装了一个事务,它允许复杂的处理指令(意味着多个SQL查询)。事务处理(IE:必须明确声明“COMMIT”或“ROLLBACK”)取决于设置。

答案 2 :(得分:3)

在理想的世界中,您选择的DBMS将是关系完整的,允许您编写任意复杂性的约束并支持多个赋值,以允许您使用简单语句随时更新数据库(即不延迟或禁用约束) 。在现实世界中,我们有SQL。

理想的SQL产品将符合完全SQL-92标准:支持CREATE ASSERTION(架构级约束),允许CHECK约束中的子查询并支持在事务中推迟约束以启用要在不禁用约束的情况下更新数据库。遗憾的是,Oracle还没有达到这种功能水平。因此,在现实世界中,我们有时必须使用过程代码来“管理”更新,同时保持数据的完整性。

例如,考虑一个真正的一对一关系,足够普遍,业务规则如下:

  

数据库包含详细信息   三个员工和项目   relvars:EMP,PROJ和EMP_PROJ。一切   项目必须至少有一个   员工和每个项目附件   必须参考现有项目。   当项目至少创建一个时   员工必须同时进行   附在它上面。

在Oracle中,您不能编写ASSERTIONCHECK来强制执行表间约束,因此在这种情况下推迟约束的能力不大。

可以使用适当的参数编写PROCEDURE来创建项目并将一名员工分配给项目的方法。这样的程序将按此顺序(伪代码):

1)开始交易;

2)插入PROJ;

3)插入EMP_PROJ;

4)测试不符合名义约束的数据,例如

EXISTS (
        SELECT * 
          FROM PROJ
         WHERE NOT EXISTS (
                           SELECT * 
                             FROM EMP_PROJ
                            WHERE EMP_PROJ.project_code = PROJ.project_code
                          )
       );

5)如果测试发现非法数据,则回滚否则提交事务。

如果约束受到影响,则回滚事务并保持数据完整性(尽管您可能希望更优雅地处理此类验证失败:)

从项目中删除员工以防止在项目中删除最后剩余的分配员工时(如果要阻止员工删除或者项目是否应该删除),需要执行类似的过程?请问您的设计师: )

因为只能通过执行这样的过程代码来确保数据完整性,所以每个人都可以将它封装在数据库中的PROCEDURE对象中,然后将PROCEDURE的'执行'权限授予用户(而不是在基础表上授予增强特权)。要强制一组用户(例如最终用户应用程序)仅使用PROCEDURE更新数据,应撤消其对基础表的更新权限。这可能需要提供进一步的“帮助”功能,例如将员工分配到项目并删除项目。如果您购买“通过存储过程进行的所有数据库访问”,那么您无论如何都会这样做。