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

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.

Related

PL/SQL: numeric or value error - ORA-06502

Im am keep getting ORA-06502: PL/SQL: numeric or value error: character string buffer too small. Here is what i do.
CREATE OR REPLACE TYPE t_new_var AS OBJECT (
var_v_1 varchar2(6 char),
var_v_2 varchar2(4 char),
var_v_3 varchar2(4 char),
CONSTRUCTOR FUNCTION t_new_var(SELF IN OUT NOCOPY t_new_var) RETURN SELF AS RESULT
);
CREATE OR REPLACE TYPE t_old AS OBJECT (
var_v_1 number(3), -- nullable
var_v_2 number(8), -- nullable
var_v_3 number(2), -- nullable
CONSTRUCTOR FUNCTION t_old(SELF IN OUT NOCOPY t_old) RETURN SELF AS RESULT
);
In a procedure:
SELECT
TO_CHAR(t_old.var_v_1) AS one,
TO_CHAR(t_old.var_v_2) AS two,
TO_CHAR(t_old.var_v_3) AS three
INTO
t_new_v.var_v_1,
t_new_v.var_v_2,
t_new_v.var_v_3
FROM DUAL;
What is the problem here ? I have tried, CAST DECODE as well NVL same error
You tried to assign a value to a varchar variable, but the value is larger than the variable can handle.
You are going to select
TO_CHAR(t_old.var_v_2) AS two - number(8)
into
var_v_2 - varchar2(4 char),
You can't select 8 characters into a variable, size of 4 characters.

Why getting ORA-01858: a non-numeric character was found where a numeric was expected?

I am working with xml table. I am having problem with my date type columns. Can somebody look into my code and tell me what is wrong with my code cause I can't figure it out.
My table TBL_EMP_BASIC_PROFILE is :
Name Null Type
--------------------- -------- -------------
EBASP_ID NOT NULL VARCHAR2(10)
EBASP_NAME VARCHAR2(50)
B_EBASP_NAME VARCHAR2(150)
EBASP_GENDER VARCHAR2(8)
EBASP_CATEGORY VARCHAR2(10)
EBASP_REGION_TYPE VARCHAR2(20)
EBASP_REGION_NAME VARCHAR2(50)
EBASP_SUB_REGION VARCHAR2(50)
EBASP_LOCATION VARCHAR2(100)
EBASP_DESIGNATION VARCHAR2(50)
B_EBASP_DESIGNATION VARCHAR2(150)
EBASP_DATE_OF_JOINING DATE
EBASP_GRADE NUMBER(2)
EBASP_BASIC NUMBER(7)
EBASP_PHOTO_UPLOAD VARCHAR2(500)
EBASP_CREATED_ON DATE
EBASP_CREATED_BY VARCHAR2(10)
My Package function is:
FUNCTION save_emp_basic_profile(employeeData VARCHAR2) RETURN CLOB IS
ret CLOB;
xmlData XMLType;
v_code NUMBER;
v_errm VARCHAR2(500);
BEGIN
xmlData:=XMLType(employeeData);
INSERT INTO TBL_EMP_BASIC_PROFILE SELECT temp1.* FROM XMLTABLE('/employees/employee'
PASSING xmlData
COLUMNS ebasp_id VARCHAR2(10) PATH 'ebasp_id',
ebasp_name VARCHAR2(50) PATH 'ebasp_name',
b_ebasp_name VARCHAR2(150) PATH 'b_ebasp_name',
ebasp_gender VARCHAR2(8) PATH 'ebasp_gender',
ebasp_category VARCHAR2(10) PATH 'ebasp_category',
ebasp_region_type VARCHAR2(50) PATH 'ebasp_region_type',
ebasp_region_name VARCHAR2(50) PATH 'ebasp_region_name',
ebasp_sub_region VARCHAR2(50) PATH 'ebasp_sub_region',
ebasp_location VARCHAR2(100) PATH 'ebasp_location',
ebasp_designation VARCHAR2(50) PATH 'ebasp_designation',
b_ebasp_designation VARCHAR2(150) PATH 'b_ebasp_designation',
ebasp_date_of_joining DATE PATH 'ebasp_date_of_joining',
ebasp_grade NUMBER(2) PATH 'ebasp_grade',
ebasp_basic NUMBER(7) PATH 'ebasp_basic',
ebasp_photo_upload VARCHAR2(500) PATH 'ebasp_photo_upload',
ebasp_created_on DATE PATH 'ebasp_created_on',
ebasp_created_by VARCHAR2(50) PATH 'ebasp_created_by')temp1;
ret:=to_char(sql%rowcount);
COMMIT;
RETURN '<result><status affectedRow='||ret1||'>Success</status></result>';
DBMS_OUTPUT.PUT_LINE(ret);
EXCEPTION
WHEN OTHERS THEN
v_code := SQLCODE;
v_errm := SUBSTR(SQLERRM, 1 , 500);
DBMS_OUTPUT.PUT_LINE('Error code ' || v_code || ': ' || v_errm);
RETURN '<result><status>Error'||v_errm||'</status></result>';
END save_emp_basic_profile;
My input pl sql is:
declare
query_result clob;
begin
query_result := *package_name*.SAVE_EMP_BASIC_PROFILE
('<employees>
<employee>
<ebasp_id>1234567890</ebasp_id>
<ebasp_name></ebasp_name>
<b_ebasp_name></b_ebasp_name>
<ebasp_gender></ebasp_gender>
<ebasp_category></ebasp_category>
<ebasp_region_type></ebasp_region_type>
<ebasp_region_name></ebasp_region_name>
<ebasp_sub_region></ebasp_sub_region>
<ebasp_location></ebasp_location>
<ebasp_designation></ebasp_designation>
<b_ebasp_designation></b_ebasp_designation>
<ebasp_date_of_joining>to_date(''2-2-2016'',''DD-MM-YYYY'')</ebasp_date_of_joining>
<ebasp_grade></ebasp_grade>
<ebasp_basic></ebasp_basic>
<ebasp_photo_upload></ebasp_photo_upload>
<ebasp_created_on>to_date(''3-2-2016'',''DD-MM-YYYY'')</ebasp_created_on>
<ebasp_created_by></ebasp_created_by>
<econt_cell_number></econt_cell_number>
<econt_phone_number></econt_phone_number>
<econt_email></econt_email>
<econt_village_or_street></econt_village_or_street>
<b_econt_village_or_street></b_econt_village_or_street>
<econt_thana></econt_thana>
<b_econt_thana></b_econt_thana>
<econt_post_office></econt_post_office>
<b_econt_post_office></b_econt_post_office>
<econt_postal_code></econt_postal_code>
<b_econt_postal_code></b_econt_postal_code>
<econt_district></econt_district>
</employee>
</employees>');
end;
Only id and 1 date is given as input (id is mandatory as a primary key). But I am getting this error: Error code -1858: ORA-01858: a non-numeric character was found where a numeric was expected . Can somebody show me what is the right way to put date in a date type column. Because I have tried to_date() function but no good.
Don't put the to_date inside your xml; that way, you're pulling out a string "to_date(''2-2-2016'',''DD-MM-YYYY'')" which you're then expecting to convert into a date - ie. to_date('to_date(''''2-2-2016'''',''''DD-MM-YYYY'''')', '<default nls_date_format mask>') which I think you can see is a non-starter.
Instead, leave the date as the string, e.g.: <ebasp_date_of_joining>2-2-2016<ebasp_date_of_joining>, change the datatype of the column in the xmltable to varchar2 and then do the conversion to date as part of the insert, like so:
insert into tbl_emp_basic_profile -- where is the list of columns? You should explicitly list the columns you're inserting into, esp in production code!
select ebasp_id,
ebasp_name,
b_ebasp_name,
ebasp_gender,
ebasp_category,
ebasp_region_type,
ebasp_region_name,
ebasp_sub_region,
ebasp_location,
ebasp_designation,
b_ebasp_designation,
to_date(ebasp_date_of_joining, 'dd-mm-yyyy') ebasp_date_of_joining,
ebasp_grade,
ebasp_basic,
ebasp_photo_upload,
to_date(ebasp_created_on, 'dd-mm-yyyy') ebasp_created_on,
ebasp_created_by
from xmltable('/employees/employee'
passing xmldata
columns ebasp_id varchar2(10) path 'ebasp_id',
ebasp_name varchar2(50) path 'ebasp_name',
b_ebasp_name varchar2(150) path 'b_ebasp_name',
ebasp_gender varchar2(8) path 'ebasp_gender',
ebasp_category varchar2(10) path 'ebasp_category',
ebasp_region_type varchar2(50) path 'ebasp_region_type',
ebasp_region_name varchar2(50) path 'ebasp_region_name',
ebasp_sub_region varchar2(50) path 'ebasp_sub_region',
ebasp_location varchar2(100) path 'ebasp_location',
ebasp_designation varchar2(50) path 'ebasp_designation',
b_ebasp_designation varchar2(150) path 'b_ebasp_designation',
ebasp_date_of_joining varchar2(10) path 'ebasp_date_of_joining',
ebasp_grade number(2) path 'ebasp_grade',
ebasp_basic number(7) path 'ebasp_basic',
ebasp_photo_upload varchar2(500) path 'ebasp_photo_upload',
ebasp_created_on varchar2(10) path 'ebasp_created_on',
ebasp_created_by varchar2(50) path 'ebasp_created_by') temp1;
Even better would be to have the date mask used for each date as an attribute of each date node in the XML, so that you don't have to already know the format of the date string in advance; that way, if whatever generates the xml wants to change how they format their dates, it should be invisible to the database. I get that it may not be possible to get the XML generator to add that in, though.
in your code you use to_char instead of to_date('2-2-2016','DD-MM-YYYY'). maybe that's where the error is coming from?

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.

PL SQL Nested IF ELSE with Cursor

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

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.

Resources