2012-07-20 188 views
0

我已经编写了下面的存储过程来检索要发送到我的C#应用​​程序的DataSet的数据。Oracle存储过程问题

您能否为我的存储过程建议一个更强大的设计?我假设这不是返回记录集的最佳方式。

CREATE OR REPLACE PROCEDURE GET_EMPLOYEE_DATA 
(
    EMPLOYEE_EMAIL IN VARCHAR2, 
    EMP_RECORD_SET1 OUT SYS_REFCURSOR, 
    EMP_RECORD_SET2 OUT SYS_REFCURSOR, 
    EMP_RECORD_SET3 OUT SYS_REFCURSOR, 
    EMP_RECORD_SET4 OUT SYS_REFCURSOR 
) AS 
BEGIN 
    OPEN EMP_RECORD_SET1 FOR 

    SELECT EMPLOYEENAME AS EMP_NAME, 
     EMPLOYEELASTNAME AS EMP_LAST_NAME, 
     EMPLOYEEFIRSTNAME AS EMP_FIRST_NAME 
     FROM EMP.EMPLOYEES 
     WHERE EMP_EMAIL = EMPLOYEE_EMAIL 
     ; 

    OPEN EMP_RECORD_SET2 FOR 


     SELECT EMPLOYEEADD AS EMP_ADDRESSESS, 
     EMPLOYEECITY AS EMP_CITY, 
     EMPLOYEE_STATE AS EMP_STATE 
     FROM EMP.EMPLOYEES_ADDRESSES 
     WHERE EMP_EMAIL = EMPLOYEE_EMAIL; 

     OPEN EMP_RECORD_SET3 FOR 

     SELECT EMPLOYEEPHONE AS EMP_PHONE, 
     EMPLOYEEEXTENSION AS EMP_EXTENSION 
     FROM EMP.EMPLOYEES_CONTACTS 
     WHERE EMP_EMAIL = EMPLOYEE_EMAIL 
     ; 

     OPEN EMP_RECORD_SET4 FOR 

    SELECT EMPLOYEEJOB AS EMP_JOB, 
     EMPLOYEERESPONSIBILITIES AS EMP_RESPONSIBILITIES 
     FROM EMP.EMPLOYEES_DATA 
     WHERE EMP_EMAIL = EMPLOYEE_EMAIL 
     ; 


END GET_PROTOCOL_INFO_SP; 

我需要知道我的语法是否正确以及是否应关闭游标。我有4个不同的表格,在应用程序中调用数据。

+2

欢迎使用StackOverflow:如果您发布代码,XML或数据样本,请**在文本编辑器中突出显示这些行,然后单击编辑器工具栏上的“代码示例”按钮(“{}”)格式和语法突出显示它! – 2012-07-20 13:54:07

+0

您在客户端应用程序中如何处理这些结果?你真的提出4个完全独立的结果表吗?或者您是否呈现了员工不同属性的单一视图? EMP_EMAIL是这些表中的一个关键吗?或者是否真的有可能在所有4个表中有相同的'EMPLOYEE_EMAIL'多行?如果有多名员工使用同一封电子邮件,您如何确定客户端的哪个地址/电话等数据与哪位员工有关? – 2012-07-20 16:25:03

+0

谢谢marc_s。 @justin洞穴 - 我需要知道我的语法是否正确,以及我是否应该关闭游标。是的,我有4个不同的表,其中数据在应用程序中调用 – 2012-07-20 18:14:34

回答

0

似乎是一个足够合理的SP,如果你想获得4个不同的数据表。
根据每位员工的预期行数和应用程序需求,您还可以考虑仅检索一个已加入的数据表。

在任何情况下,你可能需要使用更有意义的名称为您的数据表(如Employees_PhonesEmployees_Addresses等)

+0

快速的问题,会有我SYS_REFCURSOR限制?如何在需要时关闭游标?请编辑我的代码以抽样。 – 2012-07-20 14:40:40

0
  • 你的语法似乎是有效的。
  • 无法关闭存储过程中的游标。由于游标正在返回给客户端,客户端应用程序负责关闭它们。假设客户端是基于标签的C#应用​​程序,C#应用程序将需要关闭游标。

在结构上,这是不寻常设计一个存储过程返回4个独立SYS_REFCURSOR参数特别是其中大多数查询似乎返回是1行的数据(假设EMP_EMAIL处于EMPLOYEES表中的键),或一个少数几行数据(例如,如果员工可能有多个地址)。如果EMP_EMAIL不是EMPLOYEES表中的关键字,我不认为客户端有办法找出哪个地址,哪个电话号码或哪个工作与哪个员工几乎肯定是一个错误。如果返回许多行,返回标量(可能为标量类型),如果您知道应该只返回一行,则返回一个由数据库中的四个表连接而成的单个SYS_REFCURSOR会更常见或者如果您确实需要返回四个独立的结果集,则需要四个独立的过程。就个人而言,如果您确实想要使用来自电话号码的单独OUT参数中的地址,但如果您的C#应用​​程序真的声明四个单独的GUI控件要显示,则可能更难映射到C#应用程序,所以我宁愿返回集合而不是SYS_REFCURSOR四个独立的结果集。

作为一般约定,我强烈建议使用某种命名约定来标识参数并将它们与列名和潜在列名分开。我会建议使用锚定类型。我会亲自使用P_前缀,像

CREATE OR REPLACE PROCEDURE GET_EMPLOYEE_DATA 
(
    P_EMPLOYEE_EMAIL IN EMP.EMPLOYEES.EMAIL%TYPE, 
    P_EMP_RECORD_SET1 OUT SYS_REFCURSOR, 
    P_EMP_RECORD_SET2 OUT SYS_REFCURSOR, 
    P_EMP_RECORD_SET3 OUT SYS_REFCURSOR, 
    P_EMP_RECORD_SET4 OUT SYS_REFCURSOR 
) 

这样做的原因命名约定是,当你在一个PL/SQL块写SQL语句,标识符首先使用列的名称解析然后使用局部变量。这导致很多人无意中在他们打算将局部变量与列名进行比较的地方编写代码,但最终将列名与自己进行比较。例如,如果我写这样的事情

CREATE OR REPLACE PROCEDURE get_employee (
    emp_email IN emp.employees.email%type, 
    rc  OUT sys_refcursor 
) 
AS 
BEGIN 
    OPEN rc 
    FOR select * 
     from emp.employees e 
     where e.emp_email = emp_email; 
END; 

很显然,我的意图是将emp_emailemployees表进行比对emp_email参数。但是,此代码最终会将employees表中的emp_email与自身进行比较,并返回emp_email不为NULL的表中的每一行。相反,如果我使用的参数

CREATE OR REPLACE PROCEDURE get_employee (
    p_emp_email IN emp.employees.email%type, 
    p_rc  OUT sys_refcursor 
) 
AS 
BEGIN 
    OPEN p_rc 
    FOR select * 
     from emp.employees e 
     where e.emp_email = p_emp_email; 
END; 

一致的命名约定则立即清楚得多,如果我无意中指的是列名时,我打算引用本地变量,反之亦然。

总的来说,我还强烈建议每个程序都是程序包的一部分。这有助于组织,允许您将相关的程序组合在一起。在这种情况下,如果您决定将此程序分成四个独立的程序,而每个程序都返回一个SYS_REFCURSOR,则此组织将会很有帮助。包允许你定义私有方法,这些私有方法只对封装中的方法有用,这有助于封装。并且包帮助依赖管理,因为当你改变包规范而不是包体时,其他包只需要重新编译。