Cursor issue with Stored Procedure - oracle

In the below oracle sql package body, I receive a "SQL Statement ignored" error and cannot determine the cause. Please see the SELECT statement of the dborLoans_cursor in the PROCEDURE updateLoansInLdcTab in the statement below:
create or replace
PACKAGE body PK_DBORUFT_SYNC AS
PROCEDURE mainProg(v_beginDate DATE, v_endDate DATE) IS
BEGIN
updateLoansInLdcTab(v_beginDate,v_endDate);
END mainProg;
FUNCTION searchForLdcToUpdate(v_beginDate DATE, v_endDate DATE) RETURN type_ref_cursor IS
v_ldcLoan type_ref_cursor;
BEGIN
DBMS_OUTPUT.ENABLE(1000000);
OPEN v_ldcLoan FOR
SELECT loan_id
FROM ldc.ldc_rel_tab
WHERE loan_id NOT IN
(SELECT loan_id
FROM dbor.vw_ldc_data dbor
WHERE dbor.closing_agent IS NOT NULL
AND dbor.closing_agent_phone IS NOT NULL
AND dbor.lock_expiration_date > sysdate)
AND TO_CHAR(request_date, 'MM/DD/YYYY') >= v_beginDate
AND TO_CHAR(request_date, 'MM/DD/YYYY') <= v_endDate;
RETURN v_ldcLoan;
END searchForLdcToUpdate;
PROCEDURE updateLoansInLdcTab(v_beginDate DATE, v_endDate DATE) is
TYPE dborLdcData IS TABLE OF dbor.vw_ldc_data%ROWTYPE;
v_ldcLoan_type_rec type_ref_cursor;
v_ldcLoanCursor_type ldcLoanCursor_type;
dborReference dborLdcData;
v_LDC_LOANID VARCHAR2(10);
v_LOAN_ID VARCHAR2(10);
v_BANKLINE VARCHAR2(20);
v_CHANNEL VARCHAR2(20);
v_PROPERTY_TYPE VARCHAR2(10);
v_STATE VARCHAR2(2);
v_STREET_NAME VARCHAR2(64);
v_FIRST_NAME VARCHAR2(64);
v_LAST_NAME VARCHAR2(64);
v_CLOSING_AGENT VARCHAR2(50);
v_CLOSING_AGENT_PHONE VARCHAR2(15);
v_REGION_CODE VARCHAR2(20);
v_CLPP_FLAG VARCHAR2(1);
v_INSTRUMENT_NAME VARCHAR2(30);
v_BROKER_OFFICER VARCHAR2(30);
v_COST_CENTER VARCHAR2(10);
v_PREPARED_BY VARCHAR2(30);
v_BUYPRICE NUMBER(9,4);
v_SRP NUMBER(8,3);
v_TOTAL_BUYPRICE NUMBER(9,4);
v_TOTAL_SRP NUMBER(8,3);
v_BRANCH_NAME VARCHAR2(30);
v_LOCK_EFFECTIVEDATE DATE;
dbor_count NUMBER;
CURSOR dborLoans_cursor IS
SELECT P.loan_id,
P.property_type,
P.state,
P.street_name,
P.close_date,
P.loan_purpose,
P.borrower_last_name,
P.borrower_first_name,
P.closing_agent,
P.closing_agent_phone,
P.region_code,
P.clpp,
P.instrument_name,
P.broker_officer,
P.lock_effective_date,
P.channel,
NVL(P.buyprice, 0) buyPrice
FROM dbor.vw_ldc_data P
LEFT JOIN dbor.wlnprogram W
ON upper(P.instrument_name) = W.ln_pgm
LEFT JOIN
(SELECT A.loan_id FROM ldc.ldc_rel_tab A WHERE A.ldc_status='LDC_PENDING'
) pend ON pend.loan_id = p.loan_id
LEFT JOIN
(SELECT DISTINCT A.loan_id
FROM ldc.ldc_rel_tab A, ldc.ldc_request_rel_tab B
WHERE A.ldc_status IN ('LDC_PENDING', 'DISBURSED','COMPLETE','RECON_PENDING','SUBMITTED','DISBURSEPAYOFF','VOIDREQUEST','FUNDS_REQUESTED')
AND A.ldc_id = B.ldc_id
AND (B.funding_reason = 'DL Payoff' OR B.funding_reason ='Original Disbursement')
) disbursed ON disbursed.loan_Id = p.loan_id
LEFT JOIN
(SELECT name, phone, agent_id, street1, city, zip, state FROM dbor.WCLOS_AGNT) wagnt
ON wagnt.agent_id=p.loan_id
LEFT JOIN
(SELECT loan,
company_name,
phone_phn,
street,
city,
zip_code,
state
FROM DBOR.WLOAN_PARTY
WHERE type='4'
) wloan ON wloan.loan =p.loan_id
WHERE P.closing_agent IS NOT NULL
AND p.loan_id not in (SELECT loan_id FROM ldc.ldc_rel_tab)
AND P.closing_agent_phone IS NOT NULL
AND P.lock_expiration_date > sysdate ;
v_dborLdcData dbor.vw_ldc_data%ROWTYPE;
BEGIN
DBMS_OUTPUT.ENABLE(1000000);
dborReference := dborLdcData();
v_ldcLoanCursor_type := searchForLdcToUpdate(v_beginDate, v_endDate);
dbor_count := 0;
WHILE dborLoans_cursor%FOUND LOOP
FETCH dborLoans_cursor INTO v_dborLdcData;
dbor_count := dbor_count + 1;
v_LOAN_ID := v_dborLdcData.LOAN_ID;
v_PROPERTY_TYPE := v_dborLdcData.property_type;
v_STATE := v_dborLdcData.state;
v_STREET_NAME := v_dborLdcData.street_name;
v_LAST_NAME := v_dborLdcData.borrower_last_name;
v_FIRST_NAME := v_dborLdcData.borrower_first_name;
v_CLOSING_AGENT := v_dborLdcData.closing_agent;
v_CLOSING_AGENT_PHONE := v_dborLdcData.closing_agent_phone;
v_CLPP_FLAG := v_dborLdcData.clpp;
v_INSTRUMENT_NAME := v_dborLdcData.INSTRUMENT_NAME;
v_BROKER_OFFICER := v_dborLdcData.BROKER_OFFICER;
v_CHANNEL := v_dborLdcData.CHANNEL;
EXECUTE IMMEDIATE 'SELECT region_code FROM dbor.Branch WHERE branch_name = '||v_dborLdcData.CHANNEL INTO v_REGION_CODE;
EXECUTE IMMEDIATE 'SELECT cost_center FROM ldc.REF_BANKLINE_REL WHERE channel = '||v_dborLdcData.CHANNEL INTO v_COST_CENTER;
EXECUTE IMMEDIATE 'SELECT bankline FROM ldc.REF_BANKLINE_REL WHERE channel = '||v_dborLdcData.CHANNEL INTO v_BANKLINE;
v_LOCK_EFFECTIVEDATE := v_dborLdcData.lock_effective_date;
v_BUYPRICE := v_dborLdcData.buyPrice;
LOOP
FETCH v_ldcLoan_type_rec INTO v_LDC_LOANID;
EXECUTE IMMEDIATE
'update ldc.ldc_rel_tabtest
set loan_id = ' ||''''|| v_LOAN_ID||''''||
',bankline = ' ||''''|| v_BANKLINE||''''||
',channel = ' ||''''||v_CHANNEL||''''||
',PROPERTY_TYPE= ' ||''''||v_PROPERTY_TYPE||''''||
',STATE = ' ||''''||v_STATE||''''||
',STREET_NAME = ' ||''''||v_STREET_NAME||''''||
',BORROWER_NAME = ' ||''''||v_LAST_NAME||','||''''||v_FIRST_NAME||''''||
',CLOSING_AGENT = ' ||''''||v_CLOSING_AGENT||''''||
',CLOSING_AGENT_PHONE = ' ||''''||v_CLOSING_AGENT_PHONE||''''||
',REGION_CODE = ' ||''''||v_REGION_CODE||''''||
',CLPP_FLAG = ' ||''''||v_CLPP_FLAG||''''||
',INSTRUMENT_NAME = ' ||''''||v_INSTRUMENT_NAME||''''||
',BROKER_OFFICER = ' ||''''||v_BROKER_OFFICER||''''||
',COST_CENTER = ' ||''''||v_COST_CENTER||''''||
',BUYPRICE = ' ||v_BUYPRICE ||
' where loan_id = ' ||v_LDC_LOANID;
END LOOP;
END LOOP;
EXCEPTION
WHEN OTHERS
THEN
DBMS_OUTPUT.PUT_LINE(SQLERRM);
END updateLoansInLdcTab;
END PK_DBORUFT_SYNC;

After quick glance at this (without running it), I would have though there are errors on the lines below as you have not put quotes around the value which is being concatenated in:
EXECUTE IMMEDIATE 'SELECT region_code FROM dbor.Branch WHERE branch_name = '||v_dborLdcData.CHANNEL INTO v_REGION_CODE;
EXECUTE IMMEDIATE 'SELECT cost_center FROM ldc.REF_BANKLINE_REL WHERE channel = '||v_dborLdcData.CHANNEL INTO v_COST_CENTER;
EXECUTE IMMEDIATE 'SELECT bankline FROM ldc.REF_BANKLINE_REL WHERE channel = '||v_dborLdcData.CHANNEL INTO v_BANKLINE;
However, from the comments above you seem to have gotten it working.
The bigger problem in this code is why are you using execute immediate at all? You don't need to, and worse you have created non scalable code as the three execute immediate statements above and the big update are not using bind variables. In PLSQL if you avoid using execute_immediate, you don't need to worry about binds at all, PLSQL does it all for you automagically.
Try converting the execute immediate select into something like:
select region_code
into v_region_code
from dbor.branch
where branch_name = v_dborLdcData.CHANNEL;
That will work find and fix the bind variable problem. Then do the same to the update:
update ldc.ldc_rel_tabtest
set loan_id = v_LOAN_ID
bankline = v_bank_line
...
...
where loan_id = v_LDC_LOANID;
The code will be simpler, easier to find errors in the SQL and more scalable.

Problem was due to missing grant on DBOR.WLOAN_PARTY.

Related

06533. 00000 - "Subscript beyond count"

I have this plsql block that populates a table with information of two other tables and I have to use a variable array:
DECLARE nombre_grupo VARCHAR2(15);
direccion_tipo direccion;
persona_tipo persona;
personas_array personas := personas();
CURSOR departamento IS
SELECT * FROM departamentos;
CURSOR empleado IS
SELECT * FROM empleados, departamentos
WHERE empleados.dept_no = departamentos.dept_no;
i INTEGER;
BEGIN
FOR departamento IN (SELECT * FROM departamentos) LOOP
nombre_grupo := departamento.dnombre;
i := 1;
personas_array := personas();
FOR empleado IN (SELECT * FROM empleados WHERE dept_no = departamento.dept_no) LOOP
direccion_tipo := DIRECCION(departamento.loc, 'NULL', empleado.dir);
personas_array(i) := PERSONA(empleado.emp_no, empleado.apellido,
direccion_tipo, empleado.fecha_alt);
i := i + 1;
END LOOP;
INSERT INTO grupos VALUES (nombre_grupo, personas_array);
END LOOP;
END;
Here's the type personas:
CREATE OR REPLACE TYPE personas AS VARRAY(5) OF PERSONA
So when I execute that block and it reaches the personas_array(i) bit, it exits the execution with "subscript beyond count" error, no matter what value of i. What am I missing?
I've already deleted and created the type personas again, I've also tried creating the type inside the procedure, but it can't insert into the table
A few tips for a SQL beginner:
Don't learn 30 years old Oracle join syntax. Use modern ANSI join syntax, i.e.
SELECT *
FROM empleados
JOIN departamentos ON empleados.dept_no = departamentos.dept_no;
Your cursors are redundant. Either use
DECLARE
CURSOR cur_departamento IS
SELECT *
FROM departamentos;
BEGIN
FOR departamento IN cur_departamento LOOP
...
END LOOP;
END;
or
DECLARE
BEGIN
FOR departamento IN (SELECT * FROM departamentos) LOOP
...
END LOOP;
END;
You can also use this:
DECLARE
CURSOR cur_empleados(d IN EMPLEADOS.DEPT_NO%TYPE) IS
SELECT *
FROM EMPLEADOS
WHERE dept_no = d;
/*
-- Do not use this!
CURSOR cur_empleados(dept_no IN EMPLEADOS.DEPT_NO%TYPE) IS
SELECT *
FROM EMPLEADOS
WHERE EMPLEADOS.dept_no = dept_no; -> will return all rows
*/
BEGIN
FOR departamento IN (SELECT * FROM departamentos) LOOP
FOR empleado IN cur_empleados(departamento.dept_no) LOOP
...
END LOOP;
END LOOP;
END;
According to my feelings, VARRAYs are often part of student material but hardly used in real life.
Using string 'NULL' is most likely not want you want. Use literal NULL, i.e.
DIRECCION(departamento.loc, NULL, empleado.dir)
Type VARRAY(5) OF PERSONA defines a varray with maximum size of 5 elements. When you initialize it with personas_array := personas(); then the actual size is 0. You need to extend the varray.
You code may look like this:
DECLARE
nombre_grupo VARCHAR2(15);
direccion_tipo direccion;
persona_tipo persona;
personas_array personas;
i INTEGER;
BEGIN
FOR departamento IN (SELECT * FROM departamentos) LOOP
nombre_grupo := departamento.dnombre;
i := 1;
personas_array := personas();
FOR empleado IN (SELECT * FROM empleados WHERE dept_no = departamento.dept_no AND ROWNUM <= 5) LOOP
direccion_tipo := DIRECCION(departamento.loc, NULL, empleado.dir);
personas_array.extend();
personas_array(i) := PERSONA(empleado.emp_no, empleado.apellido, direccion_tipo, empleado.fecha_alt);
i := i + 1;
END LOOP;
INSERT INTO grupos VALUES (nombre_grupo, personas_array);
END LOOP;
END;
Just a note, such procedure would have rather low performance. The professional way of doing it would be a Nested Table and then insert the data with a single command:
CREATE OR REPLACE TYPE personas_NT AS TABLE OF PERSONA;
INSERT INTO grupos VALUES (nombre_grupo, personas_array)
SELECT dnombre,
CAST(MULTISET(
SELECT
emp_no,
apellido,
DIRECCION(dept.loc, NULL, dir),
fecha_alt
FROM EMPLEADOS
WHERE dept_no = dept.dept_no
) AS personas_NT) AS personas_array
FROM DEPARTAMENTOS dept;
But maybe, that would be a chapter in the "advanced" SQL course.

Invalid host/bind variable name ORA-01745

Hello i m having this error :
Invalid host/bind variable name ORA-01745 at line 47
The error , from the second insert (insert into TPILVALEUR )
when i m using the procedure below , i know that it happen when we use a Oracle variable in the request but im not using it (i think in my queries) , i dont know where he found the Oracle key word in my Insert request ...
create or replace
procedure computePilotageLFIICHN (pCampagne in number)
as
cSep constant varchar2(1) := ':';
cCodeGeoTableauDep constant varchar2(3) := 'DEP';
cCodeGeoTableauReg constant varchar2(3) := 'REG';
cCodeGeoTableauNat constant varchar2(3) := 'NAT';
cCodeTypeTableauCourant constant varchar2(12) := 'LFI_ICHN';
cCodeColTheorie constant varchar2(30) := 'LFI_ICHN_THEORIE';
cCodeColDosAvecLet constant varchar2(30) := 'LFI_ICHN_DOS_AVEC_LFI';
cCodeColAEditer constant varchar2(30) := 'LFI_ICHN_A_EDITER';
cCodeColAReediter constant varchar2(30) := 'LFI_ICHN_A_REEDITER';
cCodeColEditees constant varchar2(30) := 'LFI_ICHN_EDITEES';
idTypeDemd constant varchar2(12) := '20.2010';
lDateDebut timestamp;
lTempsExec varchar2(29);
cNbEtapes constant number := 5;
lEtapeCur number := 0;
begin
PCKISISLOGGER.logavancement('Début Calcul Pilotage LFI ICHN');
pilSupprimerTdB(cCodeTypeTableauCourant,pCampagne);
pilInitialiserTdB(cCodeTypeTableauCourant,pCampagne);
EXECUTE IMMEDIATE 'create global temporary table TPILTMPLFIICHN'||pCampagne||' As SELECT * from TPILTMPLFIICHN';
EXECUTE IMMEDIATE 'insert into TPILTMPLFIICHN'||pCampagne||'(CODEDDAF,NUMEROPACAGE,CAMPAGNE) (select CODEDDAF,NUMEROPACAGE,CAMPAGNE from TPILTMPLFIICHN)';
EXECUTE IMMEDIATE 'TRUNCATE TABLE TPILTMPLFIICHN'||pCampagne;
EXECUTE IMMEDIATE 'INSERT INTO TPILTMPLFIICHN'||pCampagne||'(codeDdaf, numeroPacage, campagne)
SELECT distinct sousReq.codeDdaf, sousReq.numeroPacage, '||pCampagne||'
FROM (
SELECT dos.CODEDDAF codeDdaf, dos.numeropacage numeroPacage
FROM TSRFDOSSIERSURFACE dos,TSRFDEMANDEAIDE dem, TVSFDOSSIERVALORISATION2P dvn
WHERE dem.IDTYPEDEMANDEAIDE = '||idTypeDemd||'
AND dem.IDDOSSIERSURFACE = dos.IDDOSSIERSURFACE
AND dos.campagne = '||pCampagne||' AND dos.DATEDERNIEREEVALUATION > dos.DATEDERNIEREMODIF and dos.DOSSIERMODIFIEAREEVALUER = 0
AND dem.DATEDERNIEREEVALUATION > dem.DATEDERNIEREMODIFICATION and dem.DOSSIERMODIFIEAREEVALUER = 0
AND dvn.ELIGIBLELFI = 1) sousReq';
-- Nombre de destinataires theoriques distincts
lEtapeCur := lEtapeCur + 1;
PCKISISLOGGER.logavancement('Etape ' || lEtapeCur || '/' || cNbEtapes || ' : Calcul du Nombre de destinataires théoriques distincts');
EXECUTE IMMEDIATE 'insert into TPILVALEUR (idValeur, idTableauDeBord, codeLigne, codeColonne, valeur)
SELECT
tab.idTableauDeBord || '||cSep||' || tmpLfi.codeDdaf || '||cSep||' || '||cCodeColTheorie||',
tab.idTableauDeBord,
tmpLfi.codeDdaf,
'||cCodeColTheorie||',
count(distinct tmpLfi.numeroPacage)
FROM
TPILTABLEAUDEBORD tab,
TPILTMPLFIICHN'||pCampagne||' tmpLfi
WHERE
tab.campagne = '||pCampagne||'
AND tmpLfi.campagne = '||pCampagne||'
AND tab.codeTypeTableauDeBord = '||cCodeTypeTableauCourant||'
AND tmpLfi.codeDdaf =
case
when tab.codeTypeGeoTableauDeBord = '||cCodeGeoTableauDep||' then tab.codeDepartement
when tab.codetypegeotableaudebord = '||cCodeGeoTableauReg||' and EXISTS(SELECT 1 FROM trefdepartement dept WHERE dept.code = tmpLfi.codeDdaf AND dept.codeRegion = tab.codeRegion) then tmpLfi.codeDdaf
when tab.codetypegeotableaudebord = '||cCodeGeoTableauNat||' then tmpLfi.codeDdaf
end
GROUP BY
tab.idTableauDeBord,
tmpLfi.codeDdaf';
EXECUTE IMMEDIATE 'drop table TPILTMPLFIICHN'||pCampagne;
PCKISISLOGGER.logavancement('Fin Calcul Pilotage LFI ICHN');
end computePilotageLFIICHN;
/
Thank you
Since you need more quotes to get literals for most of the local variables within the INSERT Statement such as
EXECUTE IMMEDIATE
'INSERT INTO TPILVALEUR (idValeur, idTableauDeBord, codeLigne, codeColonne, valeur)
SELECT
tab.idTableauDeBord || '''||cSep||''' || tmpLfi.codeDdaf || '''||cSep||''' || '''||cCodeColTheorie||''',
tab.idTableauDeBord,
tmpLfi.codeDdaf,
'''||cCodeColTheorie||''',
COUNT(DISTINCT tmpLfi.numeroPacage)
FROM
TPILTABLEAUDEBORD tab
JOIN
TPILTMPLFIICHN'||pCampagne||' tmpLfi
ON tmpLfi.codeDdaf =
CASE
WHEN tab.codeTypeGeoTableauDeBord = '''||cCodeGeoTableauDep||''' THEN tab.codeDepartement
WHEN tab.codetypegeotableaudebord = '''||cCodeGeoTableauReg||''' AND EXISTS(SELECT 1 FROM trefdepartement dept WHERE dept.code = tmpLfi.codeDdaf AND dept.codeRegion = tab.codeRegion) THEN tmpLfi.codeDdaf
WHEN tab.codetypegeotableaudebord = '''||cCodeGeoTableauNat||''' THEN tmpLfi.codeDdaf
END
WHERE tab.campagne = '''||pCampagne||'''
AND tmpLfi.campagne = '''||pCampagne||'''
AND tab.codeTypeTableauDeBord = '''||cCodeTypeTableauCourant||'''
GROUP BY tab.idTableauDeBord, tmpLfi.codeDdaf';

Oracle function, how to pass parameters to cursor and use it

Here is one of oracle functions. There is a cursor called c_adv_course_credit which receives 2 parameters. These 2 parameters are using the where statement:
WHERE
-- year
cc.year = p_year AND
-- rela_pk
cc.sequence_number = p_sequence_number AND
cc.closed_ind = 'N';
When I run it in oracle sql developer:
SET SERVEROUTPUT ON
variable res varchar2(200);
EXECUTE :res := advp_test_cursor(2018, 92919);
select :res from dual;
The result text is always "not working"
Here is the full function (not working):
CREATE OR REPLACE Function SISD_OWNER.advp_test_cursor (
p_sequence_number IN NUMBER, -- rela_pk
p_year IN NUMBER -- year
)
RETURN VARCHAR2
IS
v_return_var VARCHAR2(300) := 'not working';
CURSOR c_adv_course_credit (
p_sequence_number IN NUMBER,
p_year IN NUMBER
)
IS
SELECT
cc.EXTERNAL_COURSE_CD
FROM
adv_course_credit cc
WHERE
cc.year = p_year AND
-- rela_pk
cc.sequence_number = p_sequence_number AND
cc.closed_ind = 'N';
BEGIN
FOR v_at_rec IN c_adv_course_credit(p_sequence_number, p_year) LOOP
v_return_var := v_at_rec.EXTERNAL_COURSE_CD;
DBMS_OUTPUT.PUT_LINE('?output = ' || v_return_var);
EXIT;
END LOOP;
RETURN v_return_var;
END;
If I change the cursor to use hard-coded numbers the function works and returns actual result.
WHERE
-- year
cc.year = 2018 AND
-- rela_pk
cc.sequence_number = 92919 AND
cc.closed_ind = 'N';
Your function is defined as (ignoring the data types):
advp_test_cursor(p_sequence_number, p_year)
but you're calling it as
advp_test_cursor(2018, 92919);
which has the arguments the wrong way round. You either need to flip them:
advp_test_cursor(92919, 2018);
or use named parameter notation:
advp_test_cursor(p_year=>2018, p_sequence_number=>92919)
or indeed combine both:
advp_test_cursor(p_sequence_number=>92919, p_year=>2018)
You do not need to use cursors:
CREATE OR REPLACE Function SISD_OWNER.advp_test_cursor (
p_sequence_number IN adv_course_credit.sequence_number%TYPE,
p_year IN adv_course_credit.year%TYPE
) RETURN adv_course_credit.EXTERNAL_COURSE_CD%TYPE
IS
v_return_var adv_course_credit.EXTERNAL_COURSE_CD%TYPE;
BEGIN
SELECT EXTERNAL_COURSE_CD
INTO v_return_var
FROM adv_course_credit
WHERE year = p_year
AND sequence_number = p_sequence_number
AND closed_ind = 'N';
DBMS_OUTPUT.PUT_LINE('?output = ' || v_return_var);
RETURN v_return_var;
EXCEPTION
WHEN NO_DATA_FOUND THEN
RETURN 'Not working';
END;

ORA-01007 "variable not in select list" from dbms_sql.column_value call

I am trying to use dynamic SQL to sample all the data in a schema with a pattern:
DECLARE
xsql varchar2(5000);
c NUMBER;
d NUMBER;
col_cnt INTEGER;
f BOOLEAN;
rec_tab DBMS_SQL.DESC_TAB;
col_num NUMBER;
varvar varchar2(500);
PROCEDURE print_rec(rec in DBMS_SQL.DESC_REC) IS
BEGIN
DBMS_OUTPUT.ENABLE(1000000);
DBMS_OUTPUT.NEW_LINE;
DBMS_OUTPUT.PUT_LINE('col_type = '
|| rec.col_type);
DBMS_OUTPUT.PUT_LINE('col_maxlen = '
|| rec.col_max_len);
DBMS_OUTPUT.PUT_LINE('col_name = '
|| rec.col_name);
DBMS_OUTPUT.PUT_LINE('col_name_len = '
|| rec.col_name_len);
DBMS_OUTPUT.PUT_LINE('col_schema_name = '
|| rec.col_schema_name);
DBMS_OUTPUT.PUT_LINE('col_schema_name_len = '
|| rec.col_schema_name_len);
DBMS_OUTPUT.PUT_LINE('col_precision = '
|| rec.col_precision);
DBMS_OUTPUT.PUT_LINE('col_scale = '
|| rec.col_scale);
DBMS_OUTPUT.PUT('col_null_ok = ');
IF (rec.col_null_ok) THEN
DBMS_OUTPUT.PUT_LINE('true');
ELSE
DBMS_OUTPUT.PUT_LINE('false');
END IF;
END;
BEGIN
c := DBMS_SQL.OPEN_CURSOR;
xsql:='
WITH got_r_num AS
(
SELECT e.* -- or whatever columns you want
, ROW_NUMBER () OVER (ORDER BY dbms_random.value) AS r_num
FROM dba_tab_columns e
)
SELECT * -- or list all columns except r_num
FROM got_r_num
WHERE r_num <= 10';
DBMS_SQL.PARSE(c, xsql, DBMS_SQL.NATIVE);
d := DBMS_SQL.EXECUTE(c);
DBMS_SQL.DESCRIBE_COLUMNS(c, col_cnt, rec_tab);
LOOP
IF DBMS_SQL.FETCH_ROWS(c)>0 THEN
NULL;
-- get column values of the row
DBMS_SQL.COLUMN_VALUE(c, 2, varvar);
--dbms_output.put_line('varvar=');
--DBMS_SQL.COLUMN_VALUE(source_cursor, 2, name_var);
--DBMS_SQL.COLUMN_VALUE(source_cursor, 3, birthdate_var);
-- Bind the row into the cursor that inserts into the destination table. You
-- could alter this example to require the use of dynamic SQL by inserting an
-- if condition before the bind.
--DBMS_SQL.BIND_VARIABLE(destination_cursor, ':id_bind', id_var);
--DBMS_SQL.BIND_VARIABLE(destination_cursor, ':name_bind', name_var);
--DBMS_SQL.BIND_VARIABLE(destination_cursor, ':birthdate_bind',
--birthdate_var);
--ignore := DBMS_SQL.EXECUTE(destination_cursor);
--ELSE
-- No more rows to copy:
--EXIT;
END IF;
END LOOP;
--EXIT WHEN d != 10;
--END LOOP;
col_num := rec_tab.first;
IF (col_num IS NOT NULL) THEN
LOOP
print_rec(rec_tab(col_num));
col_num := rec_tab.next(col_num);
EXIT WHEN (col_num IS NULL);
END LOOP;
END IF;
DBMS_SQL.CLOSE_CURSOR(c);
END;
/
When I run that it gives me this error from the line with the dbms_sql.column_value call:
ORA-01007: variable not in select list
If I comment out that dbms_sql.column_value call it still errors but now with:
ORA-01002: fetch out of sequence
What am I doing wrong?
You have two problems in the code you posted. Firstly you have skipped part of the execution flow because you haven't called the DEFINE_COLUMN procedure. That is what is causing the ORA-01007 error, as the dynamic SQL processing hasn't been told about the select list columns via that call. For your current code you only need to define column 2, but assuming you will actually want to refer to the others you can define them in a loop. To treat them all as string for display you could do:
...
DBMS_SQL.PARSE(c, xsql, DBMS_SQL.NATIVE);
d := DBMS_SQL.EXECUTE(c);
DBMS_SQL.DESCRIBE_COLUMNS(c, col_cnt, rec_tab);
FOR i IN 1..col_cnt
LOOP
-- dbms_output.put_line('col_name is ' || rec_tab(i).col_name);
DBMS_SQL.DEFINE_COLUMN(c, i, varvar, 500);
END LOOP;
LOOP
IF DBMS_SQL.FETCH_ROWS(c)>0 THEN
...
If you want to do anything that needs to treat the variables as the right types you could have a local variable of each type and use the data type from the rec_tab information you already have from describe_columns to use the appropriately typed variable for each column.
The second problem, which you were hitting when you commented the column_value call, is still there once that definbe issue has been fixed. Your loop doesn't ever exit, so after you fetch the last row from the cursor you do a further invalid fetch, which throws ORA-01002. You have the code to avoid that already but it's commented out:
...
LOOP
IF DBMS_SQL.FETCH_ROWS(c)>0 THEN
-- get column values of the row
DBMS_SQL.COLUMN_VALUE(c, 2, varvar);
...
ELSE
-- No more rows to copy:
EXIT;
END IF;
END LOOP;
...
With those two changes your code runs, and dumps the view structure:
PL/SQL procedure successfully completed.
col_type = 1
col_maxlen = 30
col_name = OWNER
col_name_len = 5
col_schema_name =
col_schema_name_len = 0
col_precision = 0
col_scale = 0
col_null_ok = false
col_type = 1
col_maxlen = 30
col_name = TABLE_NAME
...
To those who find this question when accessing Oracle through ODP.NET, as I did:
We started getting this error whenever we would add column to an existing table in our application. I'm not sure what all the conditions were to make it fail, but ours were:
Run a SELECT * FROM "table".
Include a ROWNUM restriction in the WHERE clause (WHERE ROWNUM < 10).
Run that through the ODP.NET dataReader.GetSchemaTable() call.
Running unrestricted queries or running queries directly on Oracle SQL Developer did not seem to cause the error.
I've hit some pretty weird stuff in the past with Oracle connection pooling, so I eventually thought that could be the problem. The solution was to restart the web service to force all the connections to be fully dropped and recreated.
The theory is that the ODP.NET connection from the connection pool still had no idea the column existed on the table, but the column was returned by the database.

The procedure below(when i uncomment the commented parts) shows 'no data found'..?

Hi I'm trying the code the below logic..i need help..
When i run the following procedure i get all the sids along with the corresponding pid for a particular month. but when i uncomment the parts that i have commented here i get the month and year displayed and then a message saying 'no data found'. Where am i going wrong?
create or replace PROCEDURE mas(V_MONTH NUMBER DEFAULT NULL,V_YEAR NUMBER DEFAULT NULL,V_AID VARCHAR2) AS
V_MID VARCHAR2(50);
V_SID VARCHAR2(50);
v_v_month number := nvl(V_MONTH,to_number(to_char(sysdate,'mm')));
v_v_year number := nvl(V_YEAR,to_number(to_char(sysdate,'yyyy')));
v_is_sub PM.IS_SUB%TYPE;
V_DIST_s NUMBER;
V_DIST_t NUMBER;
cursor c1
is
select distinct a.mid,
b.sid
from pmt a
inner join smt b
on (a.mid = b.mid)
where a.AID = V_AID
AND A.AID = B.AID
AND EXTRACT(MONTH FROM A.RDATE)= v_v_month AND
EXTRACT(YEAR FROM A.RDATE)= v_v_year
order by mid;
BEGIN
dbms_output.put_line('month : ' || v_v_month);
dbms_output.put_line('year : ' || v_v_year);
/*
select IS_SUB into v_is_sub from program_master where pid = 'V_AID';
IF v_is_sub = 1 then
select count(*) into V_DIST_S from (select distinct sid from smt where aid = 'v_aid');
select count(*) into V_DIST_T from (select distinct sid from tm where aid = 'v_aid');
if(V_DIST_S = V_DIST_T) then
*/
for rec1 in c1
loop
dbms_output.put_line('MID : ' || rec1.MID);
dbms_output.put_line('SID : ' || rec1.SID);
end loop;
-- else
-- dbms_output.put_line('count of sids do not match');
--end if;
--else
--dbms_output.put_line('No sids available for the mentioned pid.');
--end if;
END MAS;
where pid = 'V_AID';
V_AID is a variable, however, you have enclosed it within single-quotation marks, which makes it a string. So, you are actually looking for the value 'V_AID' and not the value of the variable.
Modify it to:
select IS_SUB into v_is_sub from program_master where pid = V_AID;
And do the same wherever you have enclosed the variable in single-quotation marks.

Resources