我有三个表:
- 员工(ssn,工资(
- WORKS_ON(essn,pid,小时(
- 项目(pid,pname(
员工的示例数据:
insert into EMPLOYEE values('1011', 1000)
insert into EMPLOYEE values('1012', 1200).
WORKS_ON 的示例数据
insert into WORKS_ON values('1011',80, 60)
insert into WORKS_ON values('1012',90, 40).
项目的示例数据
insert into PROJECT values(80, A)
insert into PROJECT values(90, B).
我需要创建一个存储过程,如果工作时间超过50,则将他/她的工资设置为10%。
这就是我所做的,我在UPDATE方面遇到了问题(也许我的整个代码都错了(,我已经尝试了很多次,但仍然遇到了问题,请帮助我
CREATE OR REPLACE PROCEDURE employee_details(p_ssn IN CHAR) AS
v_ssn employee.ssn%TYPE;
v_sal employee.salary%TYPE;
w_hours works_on.hours%TYPE;
BEGIN
SELECT ssn, salary, hours
INTO v_ssn, v_sal, w_hours
FROM employee NATURAL JOIN works_on
WHERE ssn = p_ssn
AND ssn = essn;
DBMS_OUTPUT.PUT_LINE('Employee_ssn :' || v_ssn);
DBMS_OUTPUT.PUT_LINE('Employee_sal :' || v_sal);
DBMS_OUTPUT.PUT_LINE('Work_hours :' || w_hours);
IF w_hours > 60.0 THEN
v_sal := v_sal + (v_sal * .1);
END IF;
UPDATE employee
SET salary = v_sal
WHERE ssn = essn
AND ssn = p_ssn;
EXCEPTION
WHEN NO_DATA_FOUND THEN
DBMS_OUTPUT.PUT_LINE('No data found.');
WHEN TOO_MANY_ROWS THEN
DBMS_OUTPUT.PUT_LINE('Many rows fetched.');
END;
错误:
17/1 PL/SQL:SQL语句被忽略
19/13 PL/SQL:ORA-00904:"ESSN":标识符无效
我的预期结果应该是
Employee_ssn : 1011
Employee_sal : 1100
Work_hours : 60
谢谢!
您有3个结构问题阻碍了代码的运行:
- select语句有一个谓词essn=ssn,但是您的表work_hours的描述包含列名emp_ssn。因此,列essn不存在。这是导致错误的直接原因:无效的标识符基本上意味着列不存在
- 仍然在选择时,使用谓词employee natural join works_on。这将导致查询永远不会返回行。NATURAL JOIN匹配引用表中具有相同名称的所有列。但是,在引用的表中没有通用的列名
- update语句使用谓词ssn=essn。这会导致当前获取的错误,因为列/变量essn不存在
此外,即使将NATURAL JOIN更正为所需的INNER JOIN(或将emp_ssn重命名为essn(,您的示例数据也不会返回任何行,因为您在引用的表中没有匹配的数据值
除了使用dbms_output来显示值(用于调试、我推测的目的或家庭作业的一部分(之外;选择、测试和设置、更新";序列。即使工资没有重新计算,您也会更新行。但整件事都没有必要。它可以通过一个更新语句来完成。如有必要,调用例程
代码和预期结果之间也存在一致性问题。您的代码查找w_hours>60.0,但您的预测结果和样本数据表明w_hours>=60.0。即使你的描述是50。
因此,将程序简化为最低要求。(注意:提供异常消息测试了处理的行数,并引发了要由调用例程处理的适当错误。
最后,过程名称本身没有说明过程的实际操作。这在(IMHO(中是一种非常糟糕的做法。(
所以试试:
create or replace
procedure increase_salary_for_excessive_hours(p_ssn in employee.ssn%type) as
begin
update employee e
set salary = salary * 1.1
where e.ssn = p_ssn
and exists (select null
from works_hour w
where w.emp_ssn = e.ssn
and w.hours >= 60
);
if sql%rowcount < 1 then
raise no_data_found;
elsif sql%rowcount > 1 then
raise too_many_rows;
end if;
end increase_salary_for_excessive_hours;
/
注意:只有当employee.ssn重复时,才会引发异常too_many_rows。如果该列上有适当的唯一(或PK(约束,则永远不会发生。该例程不会为多个符合条件的工作小时增加too_many_rows,而是只更新员工工资一次(但请注意@astentx的警告(。
请参阅此处的演示。Demo包含一个生成DBMS_OUTPUT的测试驱动程序。DBMS_OUTPUT适用于测试/调试,但不适用于生产环境
这就引出了最后一点。如果任何一个异常被引发并按当前编写的方式处理,它将编写消息,但调用例程永远不会知道它,并认为一切都成功了。我建议你花一些时间来理解异常部分的实际作用和含义。
您编写的过程使用了不存在的表和列(根据您发布的内容(。
- 表
works_on
应为works_hour
- 您使用了
essn
;它是什么 - 样本数据不匹配;如果SSN=1011,则不能期望它联接到101,因此它不会引发ORA-01422(您使用的标记((
too_many_rows
(,而是引发no_data_found
我试图修复我认为应该修复的东西。然后编译该过程。
SQL> CREATE OR REPLACE PROCEDURE employee_details(
2 p_ssn IN CHAR
3 )AS
4
5 v_ssn employee.ssn%TYPE;
6 v_sal employee.salary%TYPE;
7 w_hours works_hour.hours%TYPE; -- works_hour, not works_on
8 BEGIN
9 SELECT ssn,
10 salary,
11 hours
12 INTO
13 v_ssn,
14 v_sal,
15 w_hours
16 FROM employee
17 JOIN works_hour on emp_ssn = ssn
18 WHERE ssn = p_ssn;
19 --AND ssn = v_ssn; -- essn;
20
21 dbms_output.put_line('Employee_ssn :' || v_ssn);
22 dbms_output.put_line('Employee_sal :' || v_sal);
23 dbms_output.put_line('Work_hours :' || w_hours);
24 IF w_hours > 60.0 THEN
25 v_sal := v_sal +(v_sal *.1);
26 END IF;
27
28 UPDATE employee
29 SET
30 salary = v_sal
31 WHERE ssn = v_ssn -- essn
32 AND ssn = p_ssn;
33
34 EXCEPTION
35 WHEN no_data_found THEN
36 dbms_output.put_line('No data found.');
37 WHEN too_many_rows THEN
38 dbms_output.put_line('Many rows fetched.');
39 END;
40 /
Procedure created.
SQL>
它甚至现在工作:
SQL> set serveroutput on
SQL>
SQL> exec employee_details('1011');
Employee_ssn :1011
Employee_sal :1000
Work_hours :60
PL/SQL procedure successfully completed.
SQL> select * From employee;
SSN SALARY
---- ----------
1011 1000
1012 1200
SQL>
我不知道这是否是你想要的。