PL / SQL错误问题

时间:2011-07-22 21:41:25

标签: sql oracle plsql

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

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;
/

当我将执行语句作为执行employeeadd('marketing','john',10)运行时;我收到以下错误。我似乎无法弄清楚如何通过错误和/或正确写出:

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

3 个答案:

答案 0 :(得分:3)

为什么li_count在BEGIN ... END块之外声明?在将它作为参数发送到sp_check_dept()之前,是否需要分配它?

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

答案 1 :(得分:2)

sp_check_dept将部门编号作为输入参数(NUMBER),并将计数作为输出参数返回。 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. 我从RETURN的IF语句中删除了employeeAdd语句。在将行插入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,那就没问题。但是如果你的程序命名约定没有模式,你就会自己开车,其他开发人员也会疯狂。

答案 2 :(得分:0)

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