我正在尝试编写一个将行插入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行
答案 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;
/
其他一些观察
RETURN
的IF语句中删除了employeeAdd
语句。在将行插入DEPARTMENTS
表之前,您几乎肯定不想在将行插入EMPLOYEE
表后退出该过程。EMPLOYEES
。您的程序使用了单数EMPLOYEE
。我没有更正,因为我不确定您发布的DDL是否不正确或您发布的程序是否不正确。sp_check_dept
作为返回计数的函数实现而不是作为具有OUT参数的过程更有意义。如果只存在一段代码以将数据返回给调用者,则应将其声明为函数。DEPT
并不是特别好。使用像DEPARTMENT_NAME
之类的东西来传达列实际代表的内容会更合适。DEPT
(即使它重命名为DEPARTMENT_NAME
)作为DEPARTMENTS
的主键和EMPLOYEES
中的外键没有多大意义。主键应该是不可变的。但是,部门的名称将随着时间的推移而改变。将DEPARTMENT_NUMBER
作为主键并将DEPARTMENT_NAME
简单地标记为唯一,这将更有意义。这将使营销部门在未来重新命名为广告时变得更加容易,因为您不必追逐所有子表来更新它们。check_dept
和add_employee
(动词后跟主语,下划线分隔单词,没有前缀)。但是,如果您想要sp_check_dept
和sp_add_employee
或checkDept
和addEmployee
,甚至sp_dept_check
和sp_employee_add
,那就没问题。但是如果你的程序命名约定没有模式,你就会自己开车,其他开发人员也会疯狂。答案 2 :(得分:0)