I tried to run an update within an cursor ('cur_palettenkosten') operation in an plsql procedure.
I narrowed down, that the enclosing cursor has data and that the update does not affect any rows (output sql%rowcount)
PROCEDURE p_ref_lschein_rueckstellungen AS
for cur_palettenkosten in (
select land, spediteur_nr, plz_von, plz_bis, preis, gueltig_von, geultig_bis, gzp.behaelter_nr
from spediteur_fahrtkosten sp,gutschrift_zuord_pal gzp
where sp.behaelter_nr = 1
)
LOOP
UPDATE lschein_rueckstellungen
SET preis = cur_palettenkosten.preis
WHERE to_number(sped_nr) = to_number(cur_palettenkosten.spediteur_nr)
AND to_number(lhm_typ) = to_number(cur_palettenkosten.behaelter_nr)
AND to_char(kst) = to_char(cur_palettenkosten.land);
dbms_output.put_line (cur_palettenkosten.spediteur_nr || ' '||cur_palettenkosten.behaelter_nr|| ' '|| cur_palettenkosten.land || sql%rowcount);
END LOOP;
COMMIT;
END p_ref_lschein_rueckstellungen;
Running the script from the editor this way:
BEGIN
p_ref_lschein_rueckstellungen;
END
does have any effect on the table 'lschein_rueckstellungen' which I wanted to update.
Running it from the same editor window like this:
BEGIN
<procedure content copied here>
END
updates the data as desired.
Are the any ideas, what I did wrong?
Could it be that you open a new session per tab? Then of course you have to commit the update!
Related
I am facing for me strange issue with following parametrical cursor.
I have defined cursor in this way:
CURSOR cur_action ( product_code VARCHAR2(100) , action_master_list VARCHAR2(100))
IS
SELECT
act.ACTION_DETAIL_KEY,
act.ACTION_MASTER_KEY,
act.PRODUCT_CODE,
act.REF_ACTION_DETAIL_KEY
FROM XMLTABLE(action_master_list) x
JOIN ETDW.MFE_AR_ACTION_DETAILS act ON TO_NUMBER(x.COLUMN_VALUE) = act.ACTION_MASTER_KEY
WHERE 1=1
AND act.LAST_FLAG = 'Y'
AND act.PRODUCT_CODE = product_code;
Then I am using it in following way:
OPEN cur_action ( iFromProductCode , iActionMasterKeyList);
LOOP
FETCH cur_action BULK COLLECT INTO vActionDetailKey, vActionMasterKey, vProductCode, vRefActionDetailKey LIMIT 100;
FOR j IN 1..cur_action%ROWCOUNT
LOOP
dbms_output.put_line('vActionDetailKey: ' || vActionDetailKey (j) ||' vActionMasterKey: '|| vActionMasterKey (j) || ' vProductCode: ' || vProductCode (j));
END LOOP;
END LOOP;
Result seems to be unfilterd. It doesnt return 3 rows as expected result (this result is returned in with cusor query, when i run in outside procedure/pl block), but it returns all rows for actions in list. So it seems, that WHERE condition "act.PRODUCT_CODE = product_code" was not applied. Why?
Thank you
Why? Because you named parameter the same as column, so Oracle reads it as if it was where 1 = 1, i.e. no filtering at all.
Rename parameters to e.g.
CURSOR cur_action ( par_product_code V
----
this
and, later,
AND act.PRODUCT_CODE = par_product_code;
----
this
I am executing a query in PL / SQL in version 7 and version 14, with a function created by me, and both bring me some results, the rest bring 0.
However, when executing the same query in Oracle SQL Developer, the query brings all the results correctly.
I executed the procedure through PL / SQL and Oracle SQL Developer as well, but then none brought me the right result, all the lines were left as "0".
I can't find the problem at all, even on Google.
Basically, the function multiplies the number of rows by columns that start with "ID_", as shown below.
Function:
CREATE OR REPLACE FUNCTION DS_FUNCESP.FNBIGB_CheckDataCells
(pOwn IN VARCHAR2,
pTab IN VARCHAR2)
RETURN NUMBER
IS
v_Qtd NUMBER;
v_str VARCHAR2(2000);
BEGIN
v_Qtd := 1;
v_str := ' SELECT
SUM((SELECT COUNT(1) AS QTY_ROWS FROM ' || pOwn || '.' || pTab || ' d WHERE d.LINORIGEM <> ''CARGA MANUAL'')) AS QTY_DATA
FROM DW_FUNCESP.D_BI_COLUMNS a
LEFT JOIN
DW_FUNCESP.D_BI_TABLES b
ON a.ID_TABLE = b.ID_TABLE
AND a.ID_OWNER = b.ID_OWNER
LEFT JOIN DW_FUNCESP.D_BI_OWNERS c
ON a.ID_OWNER = c.ID_OWNER
WHERE b.NM_TABLE = ''' || pTab || '''
AND a.IN_PRIMARYKEY = ''NAO''
AND SUBSTR(a.NM_COLUMN,1,3) = ''ID_'' ';
DBMS_OUTPUT.put_line(v_str);
EXECUTE IMMEDIATE v_str into v_Qtd ;
return (v_Qtd);
EXCEPTION WHEN OTHERS THEN
RETURN 0;
END FNBIGB_CheckDataCells;
Select statement:
SELECT
c.NM_OWNER ,
b.NM_TABLE ,
DS_FUNCESP.FNBIGB_CHECKDATACELLS(c.NM_OWNER, b.NM_TABLE) AS QTY_DATA
FROM DW_FUNCESP.D_BI_TABLES b
LEFT JOIN DW_FUNCESP.D_BI_OWNERS c
ON b.ID_OWNER = c.ID_OWNER;
Results from PL/SQL:
Results from Oracle SQL Developer:
Clearly we can see the difference from any row, the right one is the Oracle SQL Developer. So I'd like to know what is the problem, how to fix, because the procedure is adding "0" to all the rows, no matter where I run.
Reading those examples from WHEN OTHERS - A Bug, thanks to #Lalit Kumar B for that, I changed:
EXCEPTION WHEN OTHERS THEN
RETURN 0;
To:
EXCEPTION
WHEN OTHERS THEN
DBMS_OUTPUT.PUT_LINE('SQLCODE: '||SQLCODE);
DBMS_OUTPUT.PUT_LINE('Message: '||SQLERRM);
RAISE;
To find out the problem, and thanks for that I found that it was trying to count from a table where it doesn't exist anymore.
So I using an error handling as below, from #Jeffrey Kemp
EXCEPTION
WHEN OTHERS THEN
IF SQLCODE != -942 THEN
RAISE;
END IF;
Also, thanks for #Belayer, my code was the problem, agreed on that. Also, executing on both softwares, made me even more confused. I'll read also that documentation for sure.
I have created a package with two procedures and two cursors in it, but while executing the procedure, it is executed successful, but same record executed multiple times and a buffer overflow occurred.
I also tried removing the loop from the cursor but for 1 record that will be fine and for multiple record it won't work as expected.
EXPECTED
I just need to remove multiple execution of same record from the procedure where i am getting multiple execution of same record
for single procedure and single cursor it is working properly but for multiple cursor and multiple procedure i am getting problem here which caused buffer overflow too where i need different record
Is there any alternative way that I can fix the problem ?
CREATE OR REPLACE PACKAGE test.report AS
PROCEDURE distribution (
code_in IN user.test.code%TYPE,
fromdate date,
todate date
);
PROCEDURE tdvalue (
id IN user.test.custid%TYPE
);
END report;
/
Package Body
CREATE OR REPLACE PACKAGE BODY test.report as
----------VARIABLE DECLARATION----------------
code_in user.test.code%TYPE;
custidin user.test.custid%TYPE;
fromdate DATE;
todate DATE;
diff number(17,2);
---------------CURSOR DECLARATION--------------
CURSOR td_data(code_in user.test.code%TYPE,
fromdate date,
todate date
) IS
( SELECT
test.code,
COUNT(test.code) AS count,
SUM(test2.Deposit_amount) AS total,
test.currency
FROM
user.test2
JOIN user.test ON test2.acid = test.acid
WHERE
user.test2.open_effective_date BETWEEN TO_DATE(fromdate, 'dd-mm-yyyy') AND TO_DATE(todate, 'dd-mm-yyyy')
and
user.test.code = code_in
GROUP BY
test.code,test.currency
);
td__data td_data%rowtype;
CURSOR C_DATA(custidin user.test.custid%TYPE) IS SELECT
test.custid,
test2.id,
TO_DATE(test2.initial_date, 'dd-mm-yyyy') - TO_DATE(test2.end_date, 'dd-mm-yyyy') AS noofdays,
round(((test2.deposit_amount *((TO_DATE(test2.initial_date, 'dd-mm-yyyy') - TO_DATE(test2.end_date, 'dd-mm-yyyy'
)) / 365) * test4.interest_rate) / 100), 2) + test2.deposit_amount AS calculated_amount,
SUM(test.flow_amt) + test2.deposit_amount AS system_amount
FROM
user.test
JOIN user.test2 ON test3.entity_id = test2.id
WHERE
test.custid = custidin
GROUP BY
test.custid,
test2.id;
c__data c_data%ROWTYPE;
PROCEDURE distribution
(
code_in IN user.test.code%TYPE,
fromdate in date,
todate in date
)
AS
BEGIN
OPEN td_data(code_in,fromdate,todate);
loop
FETCH td_data INTO td__data;
dbms_output.put_line(td__data.code
|| ' '
|| td__data.count
|| ' '
||td__data.currency
||' '
||td__data.total
);
end loop;
CLOSE td_data;
END distribution;
PROCEDURE tdvalue (
custidin IN user.test.custid%TYPE
)
AS
BEGIN
open c_data(custidin);
fetch c_data into c__data;
loop
diff:= c__data.calculated_amount- c__data.system_amount;
dbms_output.put_line(c__data.custid
|| ' '
|| c__data.noofdays
|| ' '
|| c__data.end_date
|| ' '
|| c__data.initial_date
|| ' '
|| c__data.calculated_amount
||' '
||diff
);
end loop;
close c_data;
END tdvalue;
END report;
/
To run
ALTER SESSION set nls_date_format='dd-mm-yyyy';
SET SERVEROUTPUT ON;
EXEC REPORT.DISTRIBUTION('872328','01-02-2016','08-02-2019');
/
EXEC REPORT.tdvalue('S9292879383SS53');
Buffer overflow - ORU-10027 - happens when the total number of bytes displayed through DBMS_OUTPUT exceeds the size of the serveroutput buffer. The default is only 20000 bytes (who knows why?). Your session is using that default because of how you enable serveroutput. Clearly one record is less than 2000 and you only hit that limit when you run for multiple records.
To fix this try this
SET SERVEROUTPUT ON size unlimited
It's not actually unlimited, but the upper bound is the PGA limit (session memory) and you really shouldn't hit that limit with DBMS_OUTPUT. Apart from anything else who would read all that?
So the other problem with your code - as #piezol points out - is that your loops have no exit points. You should test whether the FETCH actually fetched anything and exit if it didn't:
loop
FETCH td_data INTO td__data;
exit when td_data%notfound;
dbms_output.put_line(td__data.code
|| ' '
|| td__data.count
|| ' '
||td__data.currency
||' '
||td__data.total
);
end loop;
Remembering to do this is just one reason why implicit cursors and cursor for loops are preferred over explicit cursors.
The second cursor loop is even worse because not only does it not have an exist point, the fetch is outside the loop. That's why you have repeated output for the same record.
So let's rewrite this ...
open c_data(custidin);
fetch c_data into c__data; -- should be inside
loop
diff:= c__data.calculated_amount- c__data.system_amount;
… as a cursor for loop:
PROCEDURE tdvalue (
custidin IN user.test.custid%TYPE
)
AS
BEGIN
for c__data in c_data(custidin)
loop
diff:= c__data.calculated_amount- c__data.system_amount;
dbms_output.put_line(c__data.custid
|| ' '
|| c__data.noofdays
|| ' '
|| c__data.end_date
|| ' '
|| c__data.initial_date
|| ' '
|| c__data.calculated_amount
||' '
||diff
);
end loop;
END tdvalue;
No need for OPEN, CLOSE or FETCH, and no need to check when the cursor is exhausted.
In PL/SQL, the preferred mechanism for setting the DBMS_OUTPUT buffer size would be within your procedure. This has the benefit of working in any client tool, such as Java or Toad (though it is still up to the client tool to retrieve the output from DBMS_OUTPUT).
DBMS_Output.ENABLE
Pass in a parameter of NULL for unlimited buffer size.
It would go like this:
BEGIN
DBMS_OUTPUT.ENABLE(NULL);
FOR I IN 1..1000 LOOP
DBMS_OUTPUT.PUT_LINE('The quick red fox jumps over the lazy brown dog.');
END LOOP;
END;
/
Bonus fact:
You can use the other functions and procedures in DBMS_OUTPUT to roll your own if you aren't using SQL*Plus or a DBMS_OUTPUT-savvy tool like Toad.
You can use the GET_LINE or GET_LINES procedures from your client code to get whatever may have been written to DBMS_OUTPUT.
GET_LINE
I'm trying to implement a cursor, & after solving many errors I've finally come to a point where it runs, but it goes into infinite loop...
I've put the image of table below as image.
Aim of cursor: to calculate bowling average & store in 'bowling_avg' column.
here's the cursor code :
DECLARE
CURSOR BOWL_AVG IS SELECT SID,MATCHES,BOWLING_AVG,WICKETS
FROM BOWLING_STATS ;
NSID BOWLING_STATS.SID%TYPE;
NMATCHES BOWLING_STATS.MATCHES%TYPE;
NBOWLING_AVG BOWLING_STATS.BOWLING_AVG%TYPE;
NWICKETS BOWLING_STATS.WICKETS%TYPE;
BEGIN
OPEN BOWL_AVG;
IF BOWL_AVG%ISOPEN THEN
LOOP
FETCH BOWL_AVG INTO NSID,NMATCHES,NBOWLING_AVG,NWICKETS;
EXIT WHEN BOWL_AVG%NOTFOUND;
IF BOWL_AVG%FOUND THEN
LOOP
UPDATE BOWLING_STATS SET BOWLING_AVG=NWICKETS/NMATCHES WHERE SID=NSID ;
EXIT WHEN BOWL_AVG%NOTFOUND;
END LOOP;
END IF;
END LOOP;
ELSE
DBMS_OUTPUT.PUT_LINE('UNABLE TO OPEN CURSOR');
END IF;
CLOSE BOWL_AVG;
END;
I'm running this in oracle database 10g.
I ask for assistance in finding the error.
Thanks in advance.
Adding whitespace to your code makes it clearer what you're doing:
declare
cursor bowl_avg is
select sid, matches, bowling_avg, wickets
from bowling_stats;
nsid bowling_stats.sid%type;
nmatches bowling_stats.matches%type;
nbowling_avg bowling_stats.bowling_avg%type;
nwickets bowling_stats.wickets%type;
begin
-- 1. Open Cursor
open bowl_avg;
-- 2. Check if Cursor is open
if bowl_avg%isopen then
-- 3. Loop
loop
-- 4. Get record
fetch bowl_avg into nsid, nmatches, nbowling_avg, nwickets;
-- 5. Exit if no records left
exit when bowl_avg%notfound;
-- 6. If there is a record
if bowl_avg%found then
-- 7. Loop
loop
update bowling_stats
set bowling_avg = nwickets / nmatches
where sid = nsid;
-- 8. Exit if there is no record.
exit when bowl_avg%notfound;
end loop;
end if;
end loop;
else
dbms_output.put_line('unable to open cursor');
end if;
close bowl_avg;
end;
/
There are a number of contradictions in there.
In 1 and 2 you're opening a cursor and then checking if there is an open cursor. A error will be raised if the cursor didn't open so you can ignore this step.
In 5 and 6 you exit if you can't fetch a new record then check if you have a record. This is a contradiction so stage 6 will (almost) always evaluate to true.
in 7 and 8 you loop, exiting when you don't have a record. As you've just checked (twice) that you do in fact have a record you'll never exit this loop.
If you insist on doing this with cursors then you can remove most of your code and it should work fine:
declare
cursor bowl_avg is
select sid, matches, bowling_avg, wickets
from bowling_stats;
nsid bowling_stats.sid%type;
nmatches bowling_stats.matches%type;
nbowling_avg bowling_stats.bowling_avg%type;
nwickets bowling_stats.wickets%type;
begin
-- 1. Open Cursor
open bowl_avg;
-- 2. Loop
loop
-- 3. Get record
fetch bowl_avg into nsid, nmatches, nbowling_avg, nwickets;
-- 4. Exit loop if there is no record.
exit when bowl_avg%notfound;
-- 5. Perform UPDATE statement.
update bowling_stats
set bowling_avg = nwickets / nmatches
where sid = nsid;
end loop;
close bowl_avg;
end;
/
As always a single UPDATE statement without using loops, cursors or PL/SQL will be significantly more effective.
Please i need help.
(I SEARCHED A lot and get more confused . )
I use Toad 9.7.25 and i made this procedure (in a package)
PROCEDURE ReportaCC(pfcorte IN DATE, lcursor IN OUT SYS_REFCURSOR)
IS
BEGIN
OPEN lcursor FOR
select c1, c3, c3 from table1 where hdate = pfcorte;
close lcursor;
END;
In toad's sql editor i´d like execute that procedure and show the cursor results in toad's datagrid:
--- I WANT THIS CODE CAN EXECUTE IN TOAD'S SQL EDITOR.
DECLARE
PFCORTE DATE;
LCURSOR SYS_REFCURSOR;
BEGIN
PFCORTE := '31/08/2012';
-- LCURSOR := NULL; -- Modify the code to initialize this parameter
mypaq.REPORTACC( TO_DATE(PFCORTE,'DD/MM/YYYY') , LCURSOR );
:to_grid := LCURSOR;
COMMIT;
END;
When i execute the script (F9), and set the variable :to_grid type cursor,
i get the next error:
"ORA-24338: statement handle not executed"
What can be the problem
Thanks in advance.
Thanks four your posts... worked fine!
But now have another question...
If i replace the simple query (select c1, c2, c3 from table...) for a mor complex like this:
PROCEDURE ReportaCC(pfcorte IN DATE, lcursor OUT SYS_REFCURSOR)
IS
BEGIN
OPEN lcursor FOR
SELECT ENC.CVEOTORGANTE, ENC.NOMBREOTORGANTE, ENC.IDENDINTIFICADORDEMEDIO, TO_CHAR(SYSDATE, 'YYYYMMDD') AS FECHAEXT, ENC.NOTAOTORGANTE,
CIRCRED.valida_cc.QUITASIGNOS(VCL.APELLIDOPATERNO) AS VAL_APELLIDOPATERNO,
CIRCRED.valida_cc.QUITASIGNOS(VCL.APELLIDOMATERNO) AS VAL_APMATERNO,
CIRCRED.valida_cc.QUITASIGNOS(VCL.APELLIDOADICIONAL) AS APELLIDOADICIONAL ,
CIRCRED.valida_cc.QUITASIGNOS(VCL.NOMBRES) AS NOMBRES,
VCL.FECHANACIMIENTO,
circred.valida_cc.valida_rfc(Vcl.rfc,'CORRIGE') AS VALRFC,
circred.valida_cc.valida_curp(VCL.CURP,'CORRIGE') AS VALCURP, VCL.NACIONALIDAD,
circred.valida_cc.valida_RESIDENCIA('ESIACOM', SC.TIPOVIV ) AS VAL_RESIDENCIA, VCL.NUMEROLICENCIACONDUCIR,
circred.valida_cc.valida_EDOCIVIL('ESIACOM', VCL.ESTADOCIVIL) AS VAL_ESTADOCIVIL, VCL.SEXO,
circred.valida_cc.valida_IFE(VCL.CLAVEELECTORIFE,'CORRIGE') AS CLAVEELECTORIFE,
VCL.NUMERODEPENDIENTES,
VCL.FECHADEFUNCION, VCL.INDICADORDEFUNCION, VCL.TIPOPERSONA,
CIRCRED.valida_cc.QUITASIGNOS(VCL.DIRECCION) AS DIRECCION,
CIRCRED.valida_cc.QUITASIGNOS(VCL.COLONIAPOBLACION) AS COLONIAPOBLACION,
CIRCRED.valida_cc.QUITASIGNOS(VCL.DELEGACIONMUNICIPIO) AS DELEGACIONMUNICIPIO,
CIRCRED.valida_cc.QUITASIGNOS(VCL.CIUDAD) AS CIUDAD,
VCL.ESTADO, circred.valida_cc.valida_cp(VCL.CP, VCL.CDGEF) AS VAL_CP, VCL.FECHARESIDENCIA,
circred.valida_cc.valida_TEL(VCL.NUMEROTELEFONO,'CORRIGE') AS VAL_TEL, circred.valida_cc.valida_TIPODOMICILIO('ESIACOM', 'C') AS VAL_TIPODOMICILIO, VCL.TIPOASENTAMIENTO,
EMP.*,
ENC.CVEOTORGANTE CVEACTUAL, ENC.NOMBREOTORGANTE, SAL.CUENTAACTUAL, SAL.TIPORESPONSABILIDAD, SAL.TIPOCUENTA, SAL.TIPOCONTRA, SAL.CLAVEUNIDADMONETARIA, SAL.VALORACTIVOVALUACION,
SAL.NUMPAGOS, SAL.FREQPAGOS,SAL.PAGOPACCL, SAL.FECHAAPERTURACUENTA,
TO_CHAR(circred.valida_cc.FUN_FULTDEPCL(sal.CLNS, sal.CDGNS, sal.CDGNS, sal.CDGCL, sal.CICLO, SAL.INICICLO, SAL.FREQPAGOS, pfcorte ), 'YYYYMMDD') AS FULTPAGO,
SAL.FECHAULTIMACOMPRA, SAL.FECHACIERRECUENTA, SAL.FECHACORTE, SAL.GARANTIA, SAL.CREDITOMAXIMO,
SAL.SALDOCL, SAL.limitecredito, SAL.SDOVENCL, SAL.NUMPAGVEN, SAL.pagoactual, SAL.HISTORICOPAG, SAL.CLAVEPREVENCION, SAL.TOTPAGREP, SAL.CLAVEANTERIOROTORGANTE,
SAL.NOMBREANTERIOROTORGANTE, SAL.NUMEROCUENTAANTERIOR,
SAL.SUMSALDO, SAL.sumsdoven, SAL.numcred, SAL.numdirecc, SAL.numempleo, SAL.numctas, ENC.NOMBREOTORGANTE, NULL AS DOMDEVOL
FROM
CIRCRED.VW_ENCABEZADO ENC,
circred.VW_DATOSPERDOM VCL,
ICARO.VW_PROYINVE SC,
CIRCRED.EMPLEO EMP,
CIRCRED.VW_SALDOINCOB SAL
WHERE SAL.FUENTEBD = 'ESIACOM'
AND SAL.CDGCL = VCL.CDGCL
AND SAL.CDGCL = SC.CDGCL(+) AND SAL.CICLO = SC.CICLO(+) and SAL.INICICLO = SC.INICIO(+)
AND SAL.FCORTE = pfcorte
AND SAL.STATUSCC IN ('INCOB', 'CIERR', 'CEROS') ;
END ReportaCC;
Why cant display the results?
(The query works fine if i execute it directly in a TOAD SQL editor)
Thanks again....!!!
After you hit F9 the "Variables" dialog appears and you select Type=Cursor from the dropdown list then press OK:
The reason you are getting the "ORA-24338: statement handle not executed" error is because you are closing your cursor before it is accessed.
This is the process that is happening:
Execute procedure
OPEN statement returns a pointer to the result set in memory (but does not return any data)
CLOSE statement discards the results before they are accessed
Procedure call ends
The client caller (in this case TOAD) attempts to access the result stream, but the pointer is invalid, so nothing can be read and the error is thrown
Solution: Remove the close lcursor; statement.
As your procedure is doing only a select statement better use a function like
CREATE or REPLACE function ReportaCC(pfcorte IN DATE)
RETURN SYS_REFCURSOR
AS
lcursor SYS_REFCURSOR;
BEGIN
OPEN lcursor FOR
select c1, c3, c3 from table1 where hdate = pfcorte;
RETURN lcursor ;
END;
/
Do not close lcursor here, close from your calling statement because if you close lcursor then you wouldn't be able to see any results.
And execute as
select ReportaCC(<>) from dual
from toad, double click cursor in datagrid to see the results.