【问题标题】:PL/SQL error questionPL/SQL 错误问题
【发布时间】:2011-07-22 21:41:24
【问题描述】:

我正在尝试编写一个将一行插入员工表的存储过程。如果部门不存在,则需要将该部门插入到部门表中。我有以下代码:

drop table employees;
drop table departments;

create table departments(
dept            varchar2(30),
dept_number     number,
dept_city       varchar2(30),
CONSTRAINT pk_dept PRIMARY KEY(dept)
);

create table employees( 
dept            varchar2(30),
employee_name   varchar2(40),
employee_id     number,
CONSTRAINT pk_id PRIMARY KEY(employee_id),
CONSTRAINT fk_dept FOREIGN KEY (dept) REFERENCES departments(dept)
);


CREATE  OR REPLACE PROCEDURE employeeadd(
a_dept    IN  VARCHAR2,
a_employee_name    IN VARCHAR2,
a_employee_id    IN NUMBER)
as
    li_count    NUMBER;
BEGIN
sp_check_dept(a_dept, li_count);    
if li_count = 0 then
INSERT INTO departments (dept) values (a_dept);
    return;
end if;
INSERT INTO employee values (a_dept, a_employee_name, a_employee_id);
end;
/

create or replace procedure sp_check_dept(a_dept IN NUMBER,
                        a_count  OUT NUMBER)
as
begin
    select count(*)
into a_count
from departments
where dept_number = a_dept;
end;
/

当我以 execute employeeadd('marketing', 'john', 10); 运行我的执行语句时我收到以下错误。我似乎无法弄清楚如何克服错误和/或正确编写:

ORA-06502:PL/SQL:数字或值错误:字符到数字的转换错误 ORA-06512: 在 "employeeadd" 第 8 行 ORA-06512: 在第 1 行

【问题讨论】:

  • sp_check_dept的定义是什么?
  • 创建或替换过程 sp_check_dept(a_dept IN NUMBER, a_count OUT NUMBER) as begin select count(*) into a_count from department where dept_number = a_dept;结尾; /
  • 如果您用换行符分隔离散的错误消息将会很有帮助。您是否收到 3 个离散错误?发布两个表“departments”和“employee”的定义以及 sp_check_dept() 过程的定义也会很有用。
  • 第一个错误“字符到数字的转换”一定是由于 a_dept IN VARCHAR2 参数,该参数被传递给 sp_check_dept(),它的第一个参数是 NUMBER。

标签: sql oracle plsql


【解决方案1】:

为什么 li_count 在 BEGIN...END 块之外声明?在将其作为参数发送给 sp_check_dept() 之前是否需要对其进行分配?

编辑:刚刚看到您的后续评论: sp_check_dept 期望一个数字作为其第一个参数;您已将 a_dept 声明为 VARCHAR。

【讨论】:

    【解决方案2】:

    sp_check_dept 将部门编号作为输入参数(数字)并返回计数作为输出参数。 employeeadd 将部门名称 (VARCHAR2) 作为第一个参数传递给 sp_check_dept。有几种方法可以解决这个问题。通常,您需要一种更一致的参数命名方法,以便更轻松地识别这些问题。

    选项 1:对两个职能都使用部门名称

    create or replace procedure sp_check_dept(p_dept_name IN departments.dept%type,
                                              p_count    OUT NUMBER)
    as
    begin
        select count(*)
          into p_count
          from departments
         where dept = p_dept_name;
    end;
    /
    
    CREATE  OR REPLACE PROCEDURE employeeadd(
      p_dept_name     IN departments.dept%type,
      p_employee_name IN employees.employee_name%type,
      p_employee_id   IN employees.employee_id%type)
    as
        li_count    NUMBER;
    BEGIN
      sp_check_dept(p_dept_name, li_count);    
      if li_count = 0 then
        INSERT INTO departments (dept) 
          VALUES (p_dept_name);
      end if;
      INSERT INTO employee(dept, employee_name, employee_id)
        VALUES (p_dept, p_employee_name, p_employee_id);
    end;
    /
    

    选项 2:将employeeAdd 中的部门名称转换为部门编号,然后再将其传递给sp_check_dept

    create or replace procedure sp_check_dept(p_dept_number IN departments.dept_number%type,
                                              p_count      OUT NUMBER)
    as
    begin
        select count(*)
          into p_count
          from departments
         where dept_number = p_dept_number;
    end;
    /
    
    CREATE OR REPLACE FUNCTION get_dept_number( p_dept_name IN departments.dept%tyep )
      RETURN departments.dept_number%type
    IS
      l_dept_number departments.dept_number%type;
    BEGIN
      SELECT dept_number
        INTO l_dept_number
        FROM departments
       WHERE dept = p_dept_name;
    
      RETURN l_dept_number
    END;
    /
    
    CREATE  OR REPLACE PROCEDURE employeeadd(
      p_dept_name     IN departments.dept%type,
      p_employee_name IN employees.employee_name%type,
      p_employee_id   IN employees.employee_id%type)
    as
        li_count    NUMBER;
    BEGIN
      sp_check_dept( get_dept_number(p_dept_name), li_count);    
      if li_count = 0 then
        INSERT INTO departments (dept) 
          VALUES (p_dept_name);
      end if;
      INSERT INTO employee(dept, employee_name, employee_id)
        VALUES (p_dept, p_employee_name, p_employee_id);
    end;
    /
    

    其他一些观察结果

    1. 我从employeeAdd 中的 IF 语句中删除了 RETURN 语句。在将行插入DEPARTMENTS 表之后,再将行插入EMPLOYEE 表之前,您几乎肯定不想退出该过程。
    2. 您的表定义使用了复数 EMPLOYEES。您的程序使用了单数 EMPLOYEE。我没有更正,因为我不确定您发布的 DDL 是否不正确,或者您发布的程序是否不正确。
    3. 一般来说,将sp_check_dept 实现为一个返回计数的函数而不是一个带有OUT 参数的过程会更有意义。如果一段代码只是为了向调用者返回数据而存在,则应将其声明为函数。
    4. 从数据模型的角度来看,列名DEPT 并不是特别好。使用 DEPARTMENT_NAME 之类的东西来传达列实际代表的内容会更合适。
    5. 从数据模型的角度来看,将 VARCHAR2 列 DEPT(即使它重命名为 DEPARTMENT_NAME)作为 DEPARTMENTS 的主键和 EMPLOYEES 中的外键没有多大意义。主键应该是不可变的。但是,部门的名称会随着时间的推移而改变。将DEPARTMENT_NUMBER 用作主键并将DEPARTMENT_NAME 简单地标记为唯一会更有意义。当营销部门在未来更名为广告时,这将变得更加容易,因为您不必追踪所有子表来更新它们。
    6. 您应该为过程选择一个命名约定并坚持下去。我更喜欢check_deptadd_employee(动词后跟主语,下划线分隔单词,没有前缀)。但是,如果您想要sp_check_deptsp_add_employeecheckDeptaddEmployee 甚至sp_dept_checksp_employee_add,那就没问题了。但是,如果您的过程命名约定没有模式,您自己和其他开发人员都会发疯。

    【讨论】:

    • 感谢贾斯汀的所有好建议!我很感激!
    【解决方案3】:

    我可以看到 2 种可能性: 1.employee 表的列顺序与您的 insert 语句不同,它试图将 dept 或 name 转换为 id 2. li_count 中设置的值不是数字,所以它试图将返回值转换为数字并给你错误

    【讨论】:

      猜你喜欢
      • 2010-11-18
      • 2021-11-29
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2013-04-09
      • 2017-09-14
      相关资源
      最近更新 更多