PL SQL Nested IF ELSE with Cursor - oracle

I have three cursors declared CUR_AD1, CUR_AD1_C, CUR_AD_2. All they contain is result coming from a 3 mere select statements which works fine.
Later on I have the following statements:
BEGIN
FOR AD1_REC IN CUR_AD1 LOOP
V_ORG_NAME := AD1_REC.ADDRESS_LINE1;
IF V_ORG_NAME = AD1_REC.ADDRESS_LINE1 THEN
INSERT INTO DSOPI_PERSON_ADDR_RULE
(CCTR_PERSON_ADDRESS_ID, CCTR_PERSON_ID, SRC_ADDRESS_LINE1, SRC_ADDRESS_LINE2, SRC_ADDRESS_LINE3, SRC_ADDRESS_LINE4,
ORG_NAME, DEPT_NAME, TGT_ADDRESS_LINE1, TGT_ADDRESS_LINE2, TGT_ADDRESS_LINE3, TGT_ADDRESS_LINE4,
STATE, CITY, COUNTRY_NAME, ZIP_CODE, EXTRACT_DATE)
VALUES
(AD1_REC.CCTR_PERSON_ADDRESS_ID, AD1_REC.CCTR_PERSON_ID, AD1_REC.ADDRESS_LINE1, AD1_REC.ADDRESS_LINE2, AD1_REC.ADDRESS_LINE3, AD1_REC.ADDRESS_LINE4,
V_ORG_NAME, '', '', AD1_REC.ADDRESS_LINE2, AD1_REC.ADDRESS_LINE3, AD1_REC.ADDRESS_LINE4,
AD1_REC.STATE, AD1_REC.CITY, AD1_REC.COUNTRY_NAME, AD1_REC.ZIP_CODE, SYSDATE);
ELSIF V_ORG_NAME = AD1_REC.ADDRESS_LINE2 THEN
FOR AD2_REC IN CUR_AD2 LOOP
INSERT INTO DSOPI_PERSON_ADDR_RULE
(CCTR_PERSON_ADDRESS_ID, CCTR_PERSON_ID, SRC_ADDRESS_LINE1, SRC_ADDRESS_LINE2, SRC_ADDRESS_LINE3, SRC_ADDRESS_LINE4,
ORG_NAME, DEPT_NAME, TGT_ADDRESS_LINE1, TGT_ADDRESS_LINE2, TGT_ADDRESS_LINE3, TGT_ADDRESS_LINE4,
STATE, CITY, COUNTRY_NAME, ZIP_CODE, EXTRACT_DATE)
VALUES
(AD2_REC.CCTR_PERSON_ADDRESS_ID, AD2_REC.CCTR_PERSON_ID, AD2_REC.ADDRESS_LINE1, AD2_REC.ADDRESS_LINE2, AD2_REC.ADDRESS_LINE3, AD2_REC.ADDRESS_LINE4,
AD2_REC.ADDRESS_LINE2, NULL, AD2_REC.TGT_ADDRESS_LINE1, NULL, AD2_REC.ADDRESS_LINE3, AD2_REC.ADDRESS_LINE4,
AD2_REC.STATE, AD2_REC.CITY, AD2_REC.COUNTRY_NAME, AD2_REC.ZIP_CODE, SYSDATE);
END LOOP;
END IF;
END LOOP;
EXCEPTION WHEN OTHERS THEN
DBMS_OUTPUT.PUT_LINE('ERROR' || SQLERRM);
RAISE;
END;
When I compile the body I keep getting the following errors:
PL/SQL: SQL Statement ignored
PLS-00302: component 'ZIP_CODE' must be declared
PL/SQL: ORA-00984: column not allowed here
There is no problem with the tables whatsoever. I think it has to do something with the how I am putting my control statements. Any help is highly appreciated.
DDL for Table DSOPI_PERSON_ADDR_RULE
CREATE TABLE "CALSEED_OWNER"."DSOPI_PERSON_ADDR_RULE"
( "CCTR_PERSON_ADDRESS_ID" NUMBER(12,0),
"CCTR_PERSON_ID" NUMBER(12,0),
"SRC_ADDRESS_LINE1" VARCHAR2(100 BYTE),
"SRC_ADDRESS_LINE2" VARCHAR2(100 BYTE),
"SRC_ADDRESS_LINE3" VARCHAR2(100 BYTE),
"SRC_ADDRESS_LINE4" VARCHAR2(100 BYTE),
"ORG_NAME" VARCHAR2(100 BYTE),
"DEPT_NAME" VARCHAR2(100 BYTE),
"TGT_ADDRESS_LINE1" VARCHAR2(100 BYTE),
"TGT_ADDRESS_LINE2" VARCHAR2(100 BYTE),
"TGT_ADDRESS_LINE3" VARCHAR2(100 BYTE),
"TGT_ADDRESS_LINE4" VARCHAR2(100 BYTE),
"STATE" VARCHAR2(100 BYTE),
"CITY" VARCHAR2(100 BYTE),
"COUNTRY_NAME" VARCHAR2(100 BYTE),
"ZIP_CODE" VARCHAR2(100 BYTE),
"EXTRACT_DATE" DATE,
"STREET" VARCHAR2(100 BYTE),
"STREET_CONTD" VARCHAR2(100 BYTE)
CURSOR CUR_AD2 IS
SELECT CCTR_PERSON_ADDRESS_ID, 'AL2' AL,ADDRESS_LINE2
FROM STG_RT2_PERSON_ADDRESS WHERE UPPER(ADDRESS_LINE2) IN
( SELECT UPPER(ORG_NAME) FROM STG_RT2_ORGANIZATION
WHERE NOT REGEXP_LIKE(ORG_NAME, '[0-9]')
AND NOT (LOWER(ORG_NAME) LIKE 'unknown' OR LOWER(ORG_NAME) LIKE 'no address%'
OR ORG_NAME ='-' OR ORG_NAME=' '));

For debugging purposes you can use
DBMS_UTILITY.format_error_backtrace;
Make sure all alias in your cursors (not only your table) match the columns you are trying to access e.g.
FOR x IN SELECT zip_code zipCode FROM myTable LOOP
dbms_output.put_line(x.zip_Code)
END LOOP;
The example breaks because x contains zipCode instead of zip_code.
With the information you provided, we can't give any further help, post a describe of your table aswell as your cursors declaration or make a compilable example.
This is useful http://sqlfiddle.com/
Edit
The problem is your cursor declaration
SELECT
CCTR_PERSON_ADDRESS_ID,
'AL2' AL,
ADDRESS_LINE2,
ZIP_CODE -- ADD THIS FOR THE ZIP CODE, YOU NEED TO ADD ALL THE OTHER COLUMNS ASWELL...
FROM
STG_RT2_PERSON_ADDRESS
WHERE
UPPER(ADDRESS_LINE2) IN
(
SELECT
UPPER(ORG_NAME)
FROM
STG_RT2_ORGANIZATION
WHERE
NOT REGEXP_LIKE(ORG_NAME, '[0-9]')
AND NOT
(
LOWER(ORG_NAME) LIKE 'unknown'
OR LOWER(ORG_NAME) LIKE 'no address%'
OR ORG_NAME ='-'
OR ORG_NAME =' '
)
);
Every CUR_AD_2 is a record on your result set, therefore it has its same number of columns and names, in your query, you have only 3 columns but you are trying to access a lot of them (like zip code) that are not in the cursor; make sure to add ZIP_CODE and all the other columns needed. Or just delete them from the INSERT statement

Please check zip_code spelling matchecs column name in the table

Related

PL/SQL XML desctructuring: XVM-01081: [XPST0081] Invalid prefix

I am trying to read xml clob file with multiple namespaces. I am just literally out of ideas, spent few hours on this.
My test case looks like:
declare
test_msg clob;
begin
test_msg := to_clob(
'
<testReq xmlns="http://test/xxx/xxx-xxx/v1">
<id>HelloWorld</id>
<numer>HelloWorld</numer>
<typ>COGR</typ>
<czyAktywny>T</czyAktywny>
<a:fieldone xmlns:a="http://xxx/yyy/zzz/v1">
<a:sym>HelloWorld</a:sym>
<a:sympod>HelloWorld</a:sympod>
</a:fieldone>
</testReq>
'
);
-- Call the function
:result := i_mypackage_pkg.odbierzReq(p_komunikatWej => test_msg,
p_logId => 12344);
end;
Where my implementation of xml_table looks like:
from xmltable(xmlnamespaces('http://test/xxx/xxx-xxx/v1' as "model"
,'http://xxx/yyy/zzz/v1' as "adres"),
'//model:testReq' passing xmlType(p_komunikatWej)
columns
id varchar2(20 char) path 'model:id'
,numer varchar2(20 char) path 'model:numer'
,typ varchar2(20 char) path 'model:typ'
,czyAktywny varchar2(1 char) path 'model:czyAktywny'
-- dane adresowe punktu poboru
,kod varchar2(7 char) path 'adres:fieldone/a:sympod'
) t;
And the exception looks like this:
XVM-01081: [XPST0081] Invalid prefix
1 declare namespace model="http://test/xxx/xxx-xxx/v1";declare namesp
- ^
I am literally out of ideas. Any help would be appreciated. Thanks
EDIT
Solved by updating namespace alias:
'http://xxx/yyy/zzz/v1' as "a"
As well as using a/adres consistently, you can simplify your paths by declaring a default namespace instead of adding model:
from xmltable(xmlnamespaces(default 'http://test/xxx/xxx-xxx/v1'
,'http://xxx/yyy/zzz/v1' as "a"),
'/testReq' passing xmlType(p_komunikatWej)
columns
id varchar2(20 char) path 'id'
,numer varchar2(20 char) path 'numer'
,typ varchar2(20 char) path 'typ'
,czyAktywny varchar2(1 char) path 'czyAktywny'
-- dane adresowe punktu poboru
,kod varchar2(7 char) path 'a:fieldone/a:sympod'
) t;
db<>fiddle demo using a CTE instead of PL/SQL.

Cast SYS_REFCURSOR to a PL/SQL Type

I have a stored procedure that calls a function that returns a SYS_REFCURSOR. The function returns a SYS_REFCURSOR because this function is also called from Java application and Java does not understand rowtype.
Here is my function.
function f_get_building(
p_building_id in T_BUILDING.ID%type
) return sys_refcursor
AS
v_cursor sys_refcursor;
BEGIN
open v_cursor for
select
BUILDING_ID,
CAMPUS_ID,
DELETE_FLAG,
max(EFFECTIVE_DATE),
END_DATE,
IMAGE_URL,
INSTITUTION_ID,
LOCAL_ID,
LOCATION_ID,
NAME
from V_BUILDING
where BUILDING_ID = p_building_id
group by
BUILDING_ID,
CAMPUS_ID,
DELETE_FLAG,
END_DATE,
IMAGE_URL,
INSTITUTION_ID,
LOCAL_ID,
LOCATION_ID,
NAME;
return v_cursor;
END f_get_building;
In another stored procedure I am also calling this function but having issues using it. Here is the stored procedure.
procedure sp_delete_building(
p_building_id in T_BUILDING.ID%type,
p_permanent_delete in boolean default false
)
AS
v_building_cur sys_refcursor;
v_building_rec V_BUILDING%rowtype;
BEGIN
-- if permanment delete
if p_permanent_delete = true
then
delete from T_BUILDING where ID = p_building_id;
-- otherwise perform soft delete
else
-- lookup
v_building_cur := f_get_building(p_building_id);
-- if cursor is empty there is nothing to do
if v_building_cur%notfound then
return;
end if;
fetch v_building_cur into v_building_rec; -- this line is where the error happens
-- if its already deleted nothing to do
if v_building_rec.DELETE_FLAG = 'Y'
then
return;
else
insert into T_BUILDING_ATTRIBUTE(BUILDING_ID,EFFECTIVE_DATE,DELETE_FLAG,
IMAGE_URL,LOCATION_ID,NAME)
values (v_building_rec.BUILDING_ID,current_timestamp,'Y',v_building_rec.IMAGE_URL
,v_building_rec.LOCATION_ID,v_building_rec."NAME");
end if;
end if;
END sp_delete_building;
I am getting the following PL/SQL stacktrace.
ORA-01722: invalid number
ORA-06512: at "OBR.PKG_BUILDING", line 114
ORA-06512: at line 8
Forgive my ignorance, this is my first project using PL/SQL, I would classify myself as a Java developer, not a database developer. Since I am selecting everything from V_BUILDING I expected I would just be able to case it as a rowtype inside the stored procedure. How can I use my function inside my stored procedure?
Update:
Here is the create statement for V_BUILDING
CREATE OR REPLACE FORCE VIEW "OBR"."V_BUILDING" ("BUILDING_ID", "LOCAL_ID", "INSTITUTION_ID", "EFFECTIVE_DATE", "END_DATE", "DELETE_FLAG", "CAMPUS_ID", "LOCATION_ID", "IMAGE_URL", "NAME") AS
SELECT
ba.BUILDING_ID,
b.LOCAL_ID,
b.INSTITUTION_ID,
ba.EFFECTIVE_DATE,
NVL(MIN(ba2.EFFECTIVE_DATE - INTERVAL '0.000001' SECOND),TO_DATE('31-DEC-9999', 'DD-MON-YYYY')) AS END_DATE,
ba.DELETE_FLAG,
ba.CAMPUS_ID,
ba.LOCATION_ID,
ba.IMAGE_URL,
ba.NAME
FROM
T_BUILDING b
INNER JOIN T_BUILDING_ATTRIBUTE ba
ON b.ID = ba.BUILDING_ID
LEFT JOIN T_BUILDING_ATTRIBUTE ba2
ON ba.BUILDING_ID = ba2.BUILDING_ID
AND ba2.EFFECTIVE_DATE > ba.EFFECTIVE_DATE
GROUP BY
ba.BUILDING_ID,
b.LOCAL_ID,
b.INSTITUTION_ID,
ba.EFFECTIVE_DATE,
ba.DELETE_FLAG,
ba.CAMPUS_ID,
ba.LOCATION_ID,
ba.IMAGE_URL,
ba.NAME
ORDER BY ba.BUILDING_ID, ba.EFFECTIVE_DATE DESC;
Update 2:
Here is a screenshot of the types in the view
CAMPUS_ID - NUMBER(10)
LOCATION_ID - NUMBER(10)
IMAGE_URL - VARCHAR(500)
NAME - VARCHAR(255)
BUILDING_ID - NUMBER(10)
LOCAL_ID - VARCHAR(30)
INSTITUTION_ID - NUMBER(10)
EFFECTIVE_DATE - TIMESTAMP(6)
END_DATE - TIMESTAMP (6)
DELETE_FLAG - CHAR(1)
Here are the list of columns and their datatypes as returned by the view and the ref cursor:
LIST OF COLS FROM VIEW DATATYPE FROM VIEW LIST OF COLS FROM CURSOR DATATYPE FROM CURSOR
---------------------- ------------------ ------------------------ --------------------
BUILDING_ID NUMBER(10) BUILDING_ID NUMBER(10)
LOCAL_ID VARCHAR(30) CAMPUS_ID NUMBER(10)
INSTITUTION_ID NUMBER(10) DELETE_FLAG CHAR(1)
EFFECTIVE_DATE TIMESTAMP(6) max(EFFECTIVE_DATE) TIMESTAMP(6)
END_DATE TIMESTAMP(6) END_DATE TIMESTAMP(6)
DELETE_FLAG CHAR(1) IMAGE_URL VARCHAR(500)
CAMPUS_ID NUMBER(10) INSTITUTION_ID NUMBER(10)
LOCATION_ID NUMBER(10) LOCAL_ID VARCHAR(30)
IMAGE_URL VARCHAR(500) LOCATION_ID NUMBER(10)
NAME VARCHAR(255) NAME VARCHAR(255)
They are not the same, yet by using the V_BUILDING%ROWTYPE in your sp_delete_building procedure, you're treating the ref cursor results as if the column order is the same as that of the view.
You can see that there are several mismatches between the datatypes of the view and the cursor select lists - it's probably the "LOCATION_ID/LOCAL_ID" mismatch that's causing the invalid number error that you're seeing.
You either need to change the order of your ref cursor so that the list of columns is returned in the same order as that of the view, or to explicitly list the columns of the cursor in the v_building_rec record type.
As an aside, you should give your max(EFFECTIVE_DATE) column in the refcursor an alias.

Is it possible to insert a record with rowtype X into a table with rowtype Y?

I'm stuck with something really weird.
Yesterday I was able to produce a procedure like this:
create or replace PROCEDURE proc
IS
CURSOR CUR
IS
SELECT * FROM PROVA
WHERE STATUS = 'X';
BEGIN
FOR H IN CUR
LOOP
BEGIN
INSERT INTO PROVA2 VALUES H;
DELETE FROM PROVA WHERE ID = H.ID;
COMMIT;
END;
END LOOP;
END;
Where PROVA is defined as:
CREATE TABLE PROVA
( "ELEMENTO" VARCHAR2(20 BYTE),
"DATO" VARCHAR2(20 BYTE),
"NUMERO_TENTATIVI" NUMBER(8,0),
"STATUS" VARCHAR2(1000 BYTE),
"ID" NUMBER(*,0)
)
and PROVA2 is defined as:
CREATE TABLE PROVA
( "ELEMENTO" VARCHAR2(20 BYTE),
"DATO" VARCHAR2(20 BYTE),
"NUMERO_TENTATIVI" NUMBER(8,0),
"STATUS" VARCHAR2(1000 BYTE),
"ID" NUMBER(*,0)
"DATE_TIME" TIMESTAMP (6) DEFAULT CURRENT_TIMESTAMP
)
Unfortunately, my mistake, I didn't save and commit the correct procedure so now I'm stuck with the old one (where, when I do the insert, I have to specify every column...
INSERT INTO PROVA2(bla,bla,bla...)
VALUES (bla,bla,bla...);
I'd like the INSERT part to abstract from the table structure and I searched everywhere but I didn't find any evidence on the error that the first PROCEDURE I posted gives me, which is:
ORA-00947: not enough values
So my question is: is it possible to insert a complete record from a table X into a table Y, which has the same columns except DATE_TIME that has a default value (and I don't want to modify...).
I hope that this isn't messy and I searched everywhere on the internet about this with no luck.
Thanks.
EDIT:
To summarize:
given a table A that has foo,bar,foobar as columns, where foobar has a default value: can I insert a record 'x' from a table B that has foo,bar as columns by using:
insert into A values x
Thanks
You can use a view to do that:
create table tmp(
id number
);
create table tmp1(
id number,
dt date default sysdate
);
create view tmp1_vw as select id from tmp1;
insert into tmp1_vw values (1);
result:
table TMP created.
table TMP1 created.
view TMP1_VW created.
1 rows inserted.
Your procedure works as well:
declare
CURSOR CUR
IS
SELECT * FROM tmp;
BEGIN
FOR H IN CUR
LOOP
BEGIN
INSERT INTO tmp1_vw VALUES H;
END;
END LOOP;
END;
And don't do commit after every statement.
Follow up after 1st comment.
You have 2 tables with slightly different structure.
To solve the problem, you make a view on a second table to look exactly like first one. Then your "record types", that are derived from first table, will work on a view as well.

Oracle: Inconsistent Datatype Issue

I am getting inconsistent datatype error message and I am not sure why. I need some guidance to figure this out.
I am creating two types as:
My universe table have following columns with column type:
Column Name Data Type
PON VARCHAR2(25 BYTE)
RPON VARCHAR2(25 BYTE)
SUPPLIER_NAME VARCHAR2(255 BYTE)
SUB_SUPPLIER_NAME VARCHAR2(255 BYTE)
SOURCE_NO VARCHAR2(40 BYTE)
CKR VARCHAR2(200 BYTE)
LEC_ID VARCHAR2(200 BYTE)
ICSC VARCHAR2(10 BYTE)
ACTL_ST VARCHAR2(10 BYTE)
ADW_ST VARCHAR2(10 BYTE)
PROJ_ID VARCHAR2(100 BYTE)
MOVE_TO_INV_DT DATE
IE_DT DATE
DDD_DT DATE
EFF_BILL_DT DATE
ACTION VARCHAR2(10 BYTE)
SERVICE VARCHAR2(10 BYTE)
AFP VARCHAR2(10 BYTE)
ACNA VARCHAR2(10 BYTE)
SERVICE_NAME VARCHAR2(255 BYTE)
UPLOAD_DT DATE
PROGRAM VARCHAR2(50 BYTE)
INITIATIVE_ID NUMBER
ACOST NUMBER
ACOST_IND VARCHAR2(25 BYTE)
MAPFILE VARCHAR2(100 BYTE)
Row Type
create or replace
TYPE test_COMP_REPORT_ROW_TYPE AS OBJECT (
PON VARCHAR2(25 BYTE),
RPON VARCHAR2(25 BYTE),
VENDOR VARCHAR2(255 BYTE),
SUB_SUPPLIER VARCHAR2(255 BYTE),
SOURCE_NO VARCHAR2(40 BYTE),
ATT_CKT_ID VARCHAR2(200 BYTE),
LEC_ID VARCHAR2(200 BYTE),
ICSC VARCHAR2(10 BYTE),
STATE VARCHAR2(10 BYTE),
PROJECT_ID VARCHAR2(100 BYTE),
ACTION VARCHAR2(10 BYTE),
SERVICE_SPEED VARCHAR2(10 BYTE),
SERVICE_NAME VARCHAR(255 BYTE),
INEFFECT_DATE DATE,
EVENT_DATE DATE,
DUE_DATE DATE,
ACOST NUMBER
)
Tab Type
create or replace type test_COMP_REPORT_TAB_TYPE
AS TABLE OF test_COMP_REPORT_ROW_TYPE
Here is the Function which is using this type:
create or replace
FUNCTION test_comp_report_func
(
start_dt_h IN VARCHAR2 DEFAULT NULL,
end_dt_h IN VARCHAR2 DEFAULT NULL,
year_h IN VARCHAR2 DEFAULT NULL )
RETURN test_comp_report_tab_type pipelined
IS
e_sql LONG;
program_v VARCHAR2(10);
v_row test_comp_report_row_type := test_comp_report_row_type(NULL,
NULL,
NULL,
NULL,
NULL,
NULL,
NULL,
NULL,
NULL,
NULL,
NULL,
NULL,
NULL,
NULL,
NULL,
NULL,
NULL
);
TYPE rectyp IS REF CURSOR;
rrc_rectyp rectyp;
TYPE recordvar IS RECORD
(
PON VARCHAR2(25 BYTE),
RPON VARCHAR2(25 BYTE),
VENDOR VARCHAR2(255 BYTE),
SUB_SUPPLIER VARCHAR2(255 BYTE),
SOURCE_NO VARCHAR2(40 BYTE),
ATT_CKT_ID VARCHAR2(200 BYTE),
LEC_ID VARCHAR2(200 BYTE),
ICSC VARCHAR2(10 BYTE),
STATE VARCHAR2(10 BYTE),
PROJECT_ID VARCHAR2(100 BYTE),
ACTION VARCHAR2(10 BYTE),
SERVICE_SPEED VARCHAR2(10 BYTE),
SERVICE_NAME VARCHAR(255 BYTE),
INEFFECT_DATE DATE,
EVENT_DATE DATE,
DUE_DATE DATE,
ACOST NUMBER
);
res_rec recordvar;
BEGIN
e_sql := e_sql || 'SELECT
PON,
RPON,
SUPPLIER_NAME VENDOR,
SUB_SUPPLIER_NAME SUB_SUPPLIER,
SOURCE_NO,
CKR,
LEC_ID,
ICSC,
ACTL_ST,
ADW_ST STATE,
PROJ_ID,
ACTION,
SERVICE SPEED,
AFP,
ACNA,
SERVICE_NAME,
IE_DT,
MOVE_TO_INV_DT EVENTDAT,
DDD_DT DUEDATE,
EFF_BILL_DT,
ACOST
FROM UNIVERSE
WHERE to_date(IE_DT) between to_date(nvl(''01/01/2000'', ''01/01/2000''), ''MM/DD/YYYY'')
and to_date(nvl(''12/31/2009'', to_char(trunc(add_months(sysdate, 12),''year'')-1,''MM/DD/YYYY'')), ''MM/DD/YYYY'')
AND PROGRAM = ''T45sONNET''
AND nvl(trim(ACOST_IND), ''NULL'') not in (''INVALID-2005'')
ORDER BY ACTION';
dbms_output.put_line(e_sql);
OPEN rrc_rectyp FOR e_sql;
LOOP
FETCH rrc_rectyp INTO res_rec;
EXIT WHEN rrc_rectyp%NOTFOUND;
v_row.PON := res_rec.PON;
v_row.RPON := res_rec.RPON;
v_row.VENDOR := res_rec.VENDOR;
v_row.SUB_SUPPLIER := res_rec.SUB_SUPPLIER;
v_row.SOURCE_NO := res_rec.SOURCE_NO;
v_row.ATT_CKT_ID := res_rec.ATT_CKT_ID;
v_row.LEC_ID := res_rec.LEC_ID;
v_row.ICSC := res_rec.ICSC;
v_row.STATE := res_rec.STATE;
v_row.PROJECT_ID := res_rec.PROJECT_ID;
v_row.ACTION := res_rec.ACTION;
v_row.SERVICE_SPEED := res_rec.SERVICE_SPEED;
v_row.SERVICE_NAME := res_rec.SERVICE_NAME;
v_row.INEFFECT_DATE := res_rec.INEFFECT_DATE;
v_row.EVENT_DATE := res_rec.EVENT_DATE;
v_row.DUE_DATE := res_rec.DUE_DATE;
v_row.ACOST := res_rec.ACOST;
pipe ROW(v_row);
END LOOP;
return;
end test_comp_report_func;
I have tried to debug issue but still am not able to find my way out and would appreciate if SO Community can guide.
I first wrote an answer trying to reproduce your error but you've changed your question quite a bit so I'm starting again from scratch.
First a few remarks:
By your own account you're quite new to PL/SQL yet you're using pretty advanced features: dynamic SQL, pipelined functions, SQL Objects. Let's try to begin with something simpler at first (I'll show you how you can work with static SQL, this would be sufficient 99.9% of the time).
When you hit a problem you need to decompose your code to see what is working and what is not. That usually means simplifying your code until it is so simple it starts to work, then bring back the complex elements of your code one by one until you hit the problem again.
When you provide a test case, try to make it as simple as possible :) It'll be easier for people to help you, but more importantly in most of the cases, building the test case will help you find the solution yourself since this will force you to decompose your complex code (see previous point). My rule of thumb (FWIW) is that code that is displayed with a scroll bar (either horizontal or vertical) in SO is too big for a test case and needs to be trimmed if possible.
I ran your code and got the ORA-00932 on the fetch line. When I replace the SQL with static SQL the error is more explicit:
SQL> CREATE OR REPLACE FUNCTION test_comp_report_func
2 RETURN test_comp_report_tab_type
3 PIPELINED IS
4 TYPE recordvar IS RECORD(
5 PON VARCHAR2(25 BYTE),
(...snip...)
21 ACOST NUMBER);
22 res_rec recordvar;
23 v_row test_COMP_REPORT_ROW_TYPE;
24 CURSOR rrc_rectyp IS
25 SELECT PON,
(...snip...)
45 ACOST
46 FROM UNIVERSE;
48 BEGIN
49 OPEN rrc_rectyp;
50 LOOP
51 FETCH rrc_rectyp
52 INTO res_rec;
54 EXIT WHEN rrc_rectyp%NOTFOUND;
55 /*...*/
56 PIPE ROW(v_row);
57 END LOOP;
58 RETURN;
59 END test_comp_report_func;
60 /
Warning: Function created with compilation errors.
LINE/COL ERROR
-------- -----------------------------------------------------------------
51/7 PL/SQL: SQL Statement ignored
52/15 PLS-00386: type mismatch found at 'RES_REC' between FETCH cursor
and INTO variables
Here the problem comes from the fact that your select statement doesn't have the same number of columns as the number of fields in your record. You can use %rowcount to prevent this:
CREATE OR REPLACE FUNCTION test_comp_report_func
RETURN test_comp_report_tab_type
PIPELINED IS
v_row test_COMP_REPORT_ROW_TYPE;
CURSOR rrc_rectyp IS
SELECT PON, RPON, SUPPLIER_NAME VENDOR, SUB_SUPPLIER_NAME SUB_SUPPLIER,
SOURCE_NO, CKR, LEC_ID, ICSC, ACTL_ST, ADW_ST STATE, PROJ_ID,
ACTION, SERVICE SPEED, AFP, ACNA, SERVICE_NAME, IE_DT,
MOVE_TO_INV_DT EVENTDAT, DDD_DT DUEDATE, EFF_BILL_DT, ACOST
FROM UNIVERSE;
res_rec rrc_rectyp%ROWTYPE;
BEGIN
OPEN rrc_rectyp;
LOOP
FETCH rrc_rectyp
INTO res_rec;
EXIT WHEN rrc_rectyp%NOTFOUND;
v_row.pon := res_rec.pon;
/*...*/
PIPE ROW(v_row);
END LOOP;
RETURN;
END test_comp_report_func;
You can even fetch the SQL object directly (with an implicit cursor):
CREATE OR REPLACE FUNCTION test_comp_report_func
RETURN test_comp_report_tab_type
PIPELINED IS
BEGIN
FOR res_rec IN (SELECT test_comp_report_row_type(PON, RPON, SUPPLIER_NAME,
SUB_SUPPLIER_NAME,SOURCE_NO,
CKR, LEC_ID, ICSC, ACTL_ST,
PROJ_ID, ACTION, SERVICE,
SERVICE_NAME, IE_DT, DDD_DT,
EFF_BILL_DT, ACOST)my_object
FROM UNIVERSE) LOOP
PIPE ROW(res_rec.my_object);
END LOOP;
RETURN;
END test_comp_report_func;
You're getting the error because the SQL query in e_sql is returning four more values than are in res_rec. The cursor returns 21 columns of data but your recordvar record type only contains 17 fields.
It looks to me like the columns ACTL_ST, AFP, ACNA and EFF_BILL_DT don't map to anything in res_rec, and if you remove these from the query you should find that your function no longer reports the inconsistent datatypes error.
I would probably have implemented the function something like the following:
CREATE OR REPLACE FUNCTION test_comp_report_func_2 (
start_dt_h IN VARCHAR2 DEFAULT NULL,
end_dt_h IN VARCHAR2 DEFAULT NULL,
year_h IN VARCHAR2 DEFAULT NULL
) RETURN test_comp_report_tab_type PIPELINED
IS
CURSOR cur_res_rec IS
SELECT PON,
RPON,
SUPPLIER_NAME VENDOR,
SUB_SUPPLIER_NAME SUB_SUPPLIER,
SOURCE_NO,
CKR ATT_CKT_ID,
LEC_ID,
ICSC,
ACTL_ST,
ADW_ST STATE,
PROJ_ID AS PROJECT_ID,
ACTION,
SERVICE SERVICE_SPEED,
AFP,
ACNA,
SERVICE_NAME,
IE_DT INEFFECT_DATE,
MOVE_TO_INV_DT EVENT_DATE,
DDD_DT DUE_DATE,
EFF_BILL_DT,
ACOST
FROM UNIVERSE
WHERE TO_DATE(IE_DT) BETWEEN TO_DATE(NVL('01/01/2000', '01/01/2000'), 'MM/DD/YYYY')
AND TO_DATE(NVL('12/31/2009', TO_CHAR(TRUNC(ADD_MONTHS(SYSDATE, 12),'year') - 1,'MM/DD/YYYY')), 'MM/DD/YYYY')
AND PROGRAM = 'T45sONNET'
AND NVL(TRIM(ACOST_IND), 'NULL') NOT IN ('INVALID-2005')
ORDER BY ACTION;
v_row test_comp_report_row_type := test_comp_report_row_type(NULL, NULL, NULL, NULL,
NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL);
BEGIN
FOR res_rec IN cur_res_rec
LOOP
v_row.PON := res_rec.PON;
v_row.RPON := res_rec.RPON;
v_row.VENDOR := res_rec.VENDOR;
v_row.SUB_SUPPLIER := res_rec.SUB_SUPPLIER;
v_row.SOURCE_NO := res_rec.SOURCE_NO;
v_row.ATT_CKT_ID := res_rec.ATT_CKT_ID;
v_row.LEC_ID := res_rec.LEC_ID;
v_row.ICSC := res_rec.ICSC;
v_row.STATE := res_rec.STATE;
v_row.PROJECT_ID := res_rec.PROJECT_ID;
v_row.ACTION := res_rec.ACTION;
v_row.SERVICE_SPEED := res_rec.SERVICE_SPEED;
v_row.SERVICE_NAME := res_rec.SERVICE_NAME;
v_row.INEFFECT_DATE := res_rec.INEFFECT_DATE;
v_row.EVENT_DATE := res_rec.EVENT_DATE;
v_row.DUE_DATE := res_rec.DUE_DATE;
v_row.ACOST := res_rec.ACOST;
PIPE ROW(v_row);
END LOOP;
RETURN;
END test_comp_report_func_2;
/
Firstly, I can't honestly see the reason you're using dynamic SQL. The function above uses a 'static' SQL query, and it has the advantage that Oracle will check that this query is valid when it compiles the function. If there's an error with the query, the function won't compile. On the other hand, if you have an error with a dynamic SQL query, you won't find out that there's a problem until you run your function.
Dynamic SQL is useful if you want to change the structure of a query, e.g. to run it on different tables or change the columns used in a WHERE clause. However, most of the time you don't need to do this. Dynamic SQL is one of those things you really shouldn't use if you don't need to use it.
Also, by using FOR some_record IN some_cursor, I don't have to fiddle around with opening and closing a cursor, nor do I need to check whether there's any more data left and exit the loop if so. It also cuts out having to declare a variable for the row record (res_rec) or getting the type of this variable wrong. That is all done automatically for me.

ORACLE -1401 error

I have a stored procedure in Oracle 9i which inserts records in a table. The table has a primary key built to ensure duplicte rows doesnot exists.
I am trying to insert a record by calling this stored procedure and it works first time properly. I am again trying to insert a duplicate record and expecting unique constraint violation error. But I am getting
ORA-01401 inserted value too large for column
I knew its meaning but my query is , if the value inserted is really large then how it got successful in the first attempt.
Table is
CREATE TABLE KEY
(
ID VARCHAR2(25 BYTE),
KEY NUMBER(4) NOT NULL,
INSERT_DATE DATE,
WORK_KEY VARCHAR2(128 BYTE)
)
CREATE UNIQUE INDEX SACHINIDX ON KEY
(ID, KEY)
Call is
EXEC SQL EXECUTE
BEGIN
keyadd(:id, :key, :wkey);
END;
END-EXEC;
Stored Procedure is
PROCEDURE keyadd(id IN VARCHAR2, key IN NUMBER, wkey IN VARCHAR2)
{
BEGIN
INSERT INTO KEY
( ID,
KEY,
INSERT_DATE,
WORK_KEY)
VALUES
(
id,
key,
SYSDATE,
wkey
);
EXCEPTION
ROLLBACK;
COMMIT;
RETURN;
END;
}
First insert sqlca.sqlcode is [0]
Second insert sqlca.sqlcode is [-1401]
CREATE TABLE KEY
(
ID VARCHAR2(25 BYTE),
KEY NUMBER(4) NOT NULL,
INSERT_DATE DATE,
WORK_KEY VARCHAR2(128 BYTE)
);
CREATE UNIQUE INDEX SACHINIDX ON KEY
(ID, KEY);
create or replace PROCEDURE keyadd(id IN VARCHAR2, key IN NUMBER, wkey IN VARCHAR2)
is
BEGIN
INSERT INTO KEY
( ID,
KEY,
INSERT_DATE,
WORK_KEY)
VALUES
(
id,
key,
SYSDATE,
wkey
);
COMMIT;
-- EXCEPTION when others then
-- ROLLBACK;
end keyadd;
/
begin
keyadd('one', 1, '59FC9AD0FA5A8932836824B0489B73252C120301A2205154C096B4EB213FA983D5E500B62A469439');
keyadd('one', 1, '905BD61AAEC986ACF887DBA7C04D650B61A8818ABEBE1720D810B4A426EB9220558B530D5119315F');
end;
/
gives me the expected ORA-00001: Unique Constraint... error, not an ORA-01401. So, without further information its impossible to help.
I don't know the language the procedure was written in, but this part:
EXCEPTION
ROLLBACK;
COMMIT;
RETURN;
raises my eyebrows. Two questions:
What is this supposed to do?
Is your issue solved when you remove those lines?
My best guess is on your second try, you are providing a value for one of the other columns that is too large. Looks like this error will supersede the primary key violation.

Resources