我正在编写一个返回IN OUT游标的过程。我想检查IN参数是否值得欣赏。如果它们不是,则光标在结果的相同位置接收错误网格,其仅在欣赏参数处发生。光标是水晶报告的IN参数。
CREATE OR REPLACE PROCEDURE test_err (
p_hire_date DATE,
P_last_name IN VARCHAR2,
refcur IN OUT SYS_REFCURSOR)
IS
err_num1 PLS_INTEGER DEFAULT 0;
err_msg1 VARCHAR2 (150);
err_num2 PLS_INTEGER DEFAULT 0;
err_msg2 VARCHAR2 (150);
v_hire_date DATE;
v_last_name VARCHAR2 (150);
BEGIN
v_hire_date :=to_date(p_hire_date , 'dd/mm/yyyy');
v_last_name :=UPPER(TRIM (p_last_name));
--
IF v_hire_date < '23/01/1990'
THEN
BEGIN
err_num1 := 1;
err_msg1 := 'Try another later hire date';
END;
ELSE NULL;
END IF;
--
IF v_last_name IS NULL
THEN
BEGIN
err_num2 := 2;
err_msg2 := 'Please input employee''s last name';
END;
ELSE v_last_name := '%'||v_last_name||'%';
END IF;
--
IF (err_num1 = 0 AND err_num2 = 0)
THEN
GOTO main_task;
ELSE
GOTO err_hdle;
END IF;
<<main_task>>
OPEN refcur FOR
SELECT employee_id, last_name, hire_date
FROM hr.employees
WHERE hire_date >= v_hire_date
AND UPPER(last_name) LIKE v_last_name;
GOTO end_task;
<<err_hdle>>
OPEN refcur FOR
SELECT 'Error '||err_num1 AS employee_id, err_msg1 AS last_name,
v_hire_date AS hire_date
FROM DUAL
WHERE err_num1 <> 0
UNION ALL
SELECT 'Error '||err_num2 AS employee_id, err_msg2 AS last_name,
v_hire_date AS hire_date
FROM DUAL
WHERE err_num2 <> 0;
<<end_task>>
NULL;
END;
但是,我不得不承认这段代码看起来很傻。我想知道有没有办法使用关联数组来捕获错误,然后将它们提取到游标中而不是扩展(err_num3,err_msg3),... (err_num_n,err_msg_n)并在 err_hdle 块中连续使用UNION ALL。请帮我弄清楚这个案子。谢谢!
答案 0 :(得分:0)
首先是一些一般性意见:
v_hire_date :=to_date(p_hire_date , 'dd/mm/yyyy');
为什么要将 DATE 投放到 DATE ?
如果你只是想削减时间价值,你可以做
v_hire_date := TRUNC(p_hire_date);
IF v_hire_date < '23/01/1990' THEN
为什么要将日期值与字符串值进行比较?
最好将日期值与日期进行比较,例如
IF v_hire_date < DATE '1990 01-23' THEN
或
IF v_hire_date < TO_DATE('23/01/1990','dd/mm/yyyy') THEN
然后你不应该在你的代码中使用GOTO
,这通常被认为是糟糕的编程风格。
现在,根据您的实际问题,您可以为错误消息定义Nested Table
。
CREATE OR REPLACE TYPE err_msg_table_type AS TABLE OF hr.employees%ROWTYPE;
CREATE OR REPLACE PROCEDURE test_err (
p_hire_date DATE,
P_last_name IN VARCHAR2,
refcur IN OUT SYS_REFCURSOR)
IS
v_hire_date DATE;
v_last_name VARCHAR2 (150);
v_err_msg err_msg_table_type := err_msg_table_type();
BEGIN
v_hire_date := TRUNC(p_hire_date);
v_last_name :=UPPER(TRIM(p_last_name));
IF v_hire_date < DATE '1990-01-23' THEN
v_err_msg.EXTEND;
v_err_msg(v_err_msg.LAST).employee_id := 1;
v_err_msg(v_err_msg.LAST).last_name := 'Try another later hire date';
END IF;
IF v_last_name IS NULL THEN
v_err_msg.EXTEND;
v_err_msg(v_err_msg.LAST).employee_id := 2;
v_err_msg(v_err_msg.LAST).last_name := 'Please input employee''s last name';
END IF;
IF v_err_msg.COUNT = 0 THEN
OPEN refcur FOR
SELECT employee_id, last_name, hire_date
FROM hr.employees
WHERE hire_date >= v_hire_date
AND UPPER(last_name) LIKE '%'||v_last_name||'%';
ELSE
OPEN refcur FOR
SELECT * FROM TABLE(v_err_msg);
END IF;
END;
答案 1 :(得分:0)
感谢@Wernfried,我找到了适合我案例的答案。而不是使用关联数组,我应该部署一个嵌套表作为@Wernfried建议。但是,我必须首先创建新的用户定义对象。在@Wernfried的脚本中,他基于%ROWTYPE定义了一个新类型(err_msg_table_type),它在PL / SQL引擎中或仅在包的主体中工作。要在SQL引擎中创建新的TYPE,我们需要准确说明每个内部组件的数据类型,如创建新表的方式。
--Create table
CREATE TABLE hr.employees
(
employee_id NUMBER (6, 0),
first_name VARCHAR2 (20 BYTE),
last_name VARCHAR2 (25 BYTE),
hire_date DATE
);
--Insert records
INSERT INTO employees
VALUES(100,'King','Steven',TO_DATE('2003/06/17', 'YYYY/MM/DD'));
INSERT INTO employees
VALUES(101,'Kochhar','Neena',TO_DATE('2005/09/21', 'YYYY/MM/DD'));
INSERT INTO employees
VALUES(102,'De Haan','Lex',TO_DATE('2001/01/13', 'YYYY/MM/DD'));
INSERT INTO employees
VALUES(103,'Hunold','Alexander',TO_DATE('2006/01/03', 'YYYY/MM/DD'));
INSERT INTO employees
VALUES(104,'Ernst','Bruce',TO_DATE('2007/05/21', 'YYYY/MM/DD'));
INSERT INTO employees
VALUES(105,'Austin','David',TO_DATE('2005/06/25', 'YYYY/MM/DD'));
INSERT INTO employees
VALUES(106,'Pataballa','Valli',TO_DATE('2006/02/05', 'YYYY/MM/DD'));
INSERT INTO employees
VALUES(107,'Lorentz','Diana',TO_DATE('2007/02/07', 'YYYY/MM/DD'));
COMMIT;
--Create Objects
CREATE OR REPLACE TYPE error_set AS OBJECT (
error_id NUMBER (6, 0),
error_note VARCHAR2 (150 BYTE),
hint_note VARCHAR2 (150 BYTE)
);
CREATE OR REPLACE TYPE err_msg_tab_type IS TABLE OF error_set;
--Create procedure
CREATE OR REPLACE PROCEDURE test_err (
p_hire_date DATE,
P_last_name IN VARCHAR2,
refcur IN OUT SYS_REFCURSOR)
IS
v_hire_date DATE;
v_last_name VARCHAR2 (150);
v_err_msg err_msg_tab_type := err_msg_tab_type();
BEGIN
v_hire_date := TO_DATE(p_hire_date, 'dd/mm/yyyy');
v_last_name := UPPER(TRIM(p_last_name));
IF TRIM(p_hire_date) IS NULL THEN
v_err_msg.EXTEND;
v_err_msg(v_err_msg.LAST):= error_set (1,
'Please input the hire date',
NULL);
END IF;
IF v_hire_date < to_date ('13/01/2001','dd/mm/yyyy') THEN
v_err_msg.EXTEND;
v_err_msg(v_err_msg.LAST):= error_set (2,
'Try another later hire date',
'The oldest hire date was Jan 13, 2001');
END IF;
IF v_last_name IS NULL THEN
v_err_msg.EXTEND;
v_err_msg(v_err_msg.LAST):= error_set (3,
'Please input employee''s last name',
NULL);
END IF;
IF v_err_msg.COUNT = 0 THEN
OPEN refcur FOR
SELECT employee_id, last_name, first_name, hire_date
FROM hr.employees
WHERE hire_date >= v_hire_date
AND UPPER(last_name) LIKE '%'||v_last_name||'%';
ELSE
OPEN refcur FOR
SELECT error_id AS employee_id, error_note AS last_name,
hint_note AS first_name, v_hire_date AS hire_date
FROM TABLE(v_err_msg);
END IF;
END;
/*
--CLEAN UP after testing
DROP PROCEDURE test_err;
DROP TYPE err_msg_tab_type;
DROP TYPE error_set;
*/