i have the following procedure in oracle:
CREATE OR REPLACE procedure getPrecioMayorActual(PAR_ID_SUBASTA DECIMAL,
outi out sys_refcursor) IS
var1 decimal;
BEGIN
open outi for
SELECT (p.MONTO_OFRECIDO) into var1
FROM (SUBASTA AS s) INNER JOIN (PUJA AS p) ON (s.ID_PUJA_MAYOR =
p.ID_PUJA)
WHERE (s.ID_SUBASTA = PAR_ID_SUBASTA);
END getPrecioMayorActual;
The problem is that i'm getting the following errors:
Error(5,9): PL/SQL: SQL Statement ignored
Error(6,23): PL/SQL: ORA-00907: missing right parenthesis
I've looked everywhere but I just can't manage to see what the problem is. I'm pretty sure that it must be something quite easy, but is my first time using this and I can't find anything useful on the web. Can anyone give me a hand please? Thanks.
Just Removing as keywords is enough like the following(for table aliasing they can not used, but can be used for column aliasing, optionally):
create or replace procedure getPrecioMayorActual(PAR_ID_SUBASTA DECIMAL,
outi out sys_refcursor) IS
var1 decimal;
BEGIN
open outi for
SELECT (p.MONTO_OFRECIDO) into var1
FROM (SUBASTA s) INNER JOIN (PUJA p) ON (s.ID_PUJA_MAYOR =
p.ID_PUJA)
WHERE (s.ID_SUBASTA = PAR_ID_SUBASTA);
END getPrecioMayorActual;
In addition, even if the above syntax is correct, there's no need using paranthesis in the SELECT statement, and PROCEDURE's name at the end. Then, you may prefer writing your PROCEDURE as the following :
CREATE or REPLACE PROCEDURE getPrecioMayorActual(PAR_ID_SUBASTA DECIMAL, outi out sys_refcursor) IS
var1 decimal;
BEGIN
OPEN outi FOR
SELECT p.MONTO_OFRECIDO
INTO var1
FROM SUBASTA s INNER JOIN PUJA p ON s.ID_PUJA_MAYOR = p.ID_PUJA
WHERE s.ID_SUBASTA = PAR_ID_SUBASTA;
END;
You dont need var1 since you are passing cursor to outi.
CREATE OR REPLACE procedure
getPrecioMayorActual(PAR_ID_SUBASTA DECIMAL,
outi out sys_refcursor) AS
BEGIN
open outi for
SELECT (p.MONTO_OFRECIDO)
FROM (SUBASTA AS s) INNER JOIN (PUJA AS p) ON
(s.ID_PUJA_MAYOR =
p.ID_PUJA)
WHERE (s.ID_SUBASTA = PAR_ID_SUBASTA);
END getPrecioMayorActual;
Related
I'm trying to write a cursor. I try to match the syntax of examples but always getting compile failure on the FETCH statement.
CREATE OR REPLACE PROCEDURE IFSAPP.CLEAR_OLD_PURCHASE_ORDERS (cPlannedDelDate in varchar2) IS
-- cursor to get all the purchase orders's that have lines in released state that
CURSOR c1 IS
SELECT DISTINCT PO.ORDER_NO
FROM PURCHASE_ORDER PO, PURCHASE_ORDER_LINE_NOPART POLN
WHERE PO.ORDER_NO = POLN.ORDER_NO
AND POLN.STATE = 'Released'
AND POLN.PLANNED_DELIVERY_DATE < TO_DATE(cPlannedDelDate, 'DD/MM/YYYY');
BEGIN
DECLARE corder_no varchar2(12);
OPEN c1;
LOOP
FETCH c1 INTO corder_no;
EXIT WHEN c1%NOTFOUND;
DBMS_OUTPUT.PUT_LINE(corder_no);
END LOOP;
CLOSE c1;
END CLEAR_OLD_PURCHASE_ORDERS;
/
LINE/COL ERROR
-------- -----------------------------------------------------------------
17/9 PLS-00103: Encountered the symbol "FETCH" when expecting one of the following:
constant exception <an identifier>
<a double-quoted delimited-identifier> table columns long
double ref char time timestamp interval date binary national
character nchar
21/5 PLS-00103: Encountered the symbol "CLOSE" when expecting one of the following:
end not pragma final instantiable order overriding static
member constructor map
Can anyone see where I am going wrong?
The problem is actually where you're declaring your local variable, and the use of the DECLARE keyword. That's starting a new inner PL/SQL block, but you then have the OPEN etc. without continuing that pattern with a new BEGIN.
You don't need a sub-block though, just move the local variable declaration up before the existing BEGIN, and lose the extra DECLARE:
CREATE OR REPLACE PROCEDURE IFSAPP.CLEAR_OLD_PURCHASE_ORDERS (cPlannedDelDate in varchar2) IS
-- cursor to get all the purchase orders's that have lines in released state that
CURSOR c1 IS
SELECT DISTINCT PO.ORDER_NO
FROM PURCHASE_ORDER PO, PURCHASE_ORDER_LINE_NOPART POLN
WHERE PO.ORDER_NO = POLN.ORDER_NO
AND POLN.STATE = 'Released'
AND POLN.PLANNED_DELIVERY_DATE < TO_DATE(cPlannedDelDate, 'DD/MM/YYYY');
corder_no varchar2(12);
BEGIN
OPEN c1;
LOOP
FETCH c1 INTO corder_no;
EXIT WHEN c1%NOTFOUND;
DBMS_OUTPUT.PUT_LINE(corder_no);
END LOOP;
CLOSE c1;
END CLEAR_OLD_PURCHASE_ORDERS;
/
Incidentally, you should consider using ANSI join syntax, not the ancient comma-separated-FROM clause syntax. And it would be simpler to use an implicit cursor loop:
CREATE OR REPLACE PROCEDURE IFSAPPCLEAR_OLD_PURCHASE_ORDERS (cPlannedDelDate in varchar2) IS
BEGIN
FOR r1 IN (
SELECT DISTINCT PO.ORDER_NO
FROM PURCHASE_ORDER_LINE_NOPART POLN
JOIN PURCHASE_ORDER PO
ON PO.ORDER_NO = POLN.ORDER_NO
WHERE POLN.STATE = 'Released'
AND POLN.PLANNED_DELIVERY_DATE < TO_DATE(cPlannedDelDate, 'DD/MM/YYYY')
) LOOP
DBMS_OUTPUT.PUT_LINE(r1.order_no);
END LOOP;
END CLEAR_OLD_PURCHASE_ORDERS;
/
I'd also generally prefer to have the procedure argument declared as the data type you need, i.e. as a DATE, so you can use that in your query without converting it; and make it the caller's problem to pas the correct data type in.
I'm trying to go through c_ProdutosEncomenda cursor line by line, copying this values into a table I've created and saving those values on variables so that I can use them to call a function to give me a particular value.
Assuming all values/tables were created correctly, and that I have the "end loop" and "close c_ProdutosEncomenda" commands at the bottom, what's missing here?
It's giving out the following error:
The code in question:
create or replace Procedure proc_nota_encomenda(p_id_notaEncomenda in NotaEncomenda.cod_notaEncomenda%TYPE)
IS
cursor c_ProdutosEncomenda IS
Select Distinct f.cod_armazem, nep.cod_produto
from notaencomenda ne join
funcionario f on ne.cod_funcionario=f.cod_funcionario
join NotaEncomenda_Produto nep on ne.cod_notaencomenda=nep.cod_notaencomenda;
ex_cod_notaEcomenda_n_existe EXCEPTION;
codigo_encomenda number;
ProdutosEncomenda c_ProdutosEncomenda%ROWTYPE;
stockArmazem number;
stockMinimo number;
stockPedido number;
armazem number;
produto number;
Begin
Select cod_notaencomenda into codigo_encomenda from NotaEncomenda where cod_notaEncomenda=p_id_notaEncomenda;
If (codigo_encomenda!=p_id_notaEncomenda) THEN
raise ex_cod_notaEcomenda_n_existe;
end if;
Open c_ProdutosEncomenda;
Loop
Fetch c_ProdutosEncomenda INTO ProdutosEncomenda;
Exit when c_ProdutosEncomenda%NotFound;
Select cod_armazem from ProdutoEncomenda into armazem;
Select cod_produto from ProdutosEncomenda into produto;
stockArmazem:= FUNC_STOCK_ARTIGO_ARMAZEM(produto,armazem);
Select stock_minimo INTO stockMinimo FROM Stock where Produto_cod_produto=ProdutosEncomenda.cod_produto
AND Armazem_cod_Armazem=ProdutosEncomenda.cod_armazem;
Select quantidade INTO stockPedido FROM NotaEncomenda_Produto WHERE cod_produto=ProdutosEncomenda.cod_produto
AND cod_notaEncomenda=p_id_notaEncomenda;
If stockArmazem-stockPedido<stockMinimo THEN
Insert into ProdutosEmFalta Values (ProdutosEncomenda.cod_produto,p_id_notaEncomenda,stockPedido);
Else
Insert into GuiaSaida (cod_notaEncomenda) Values (ProdutosEncomenda.cod_produto);
Insert into ZonaArmazem_Produto_GuiaSaida (cod_produto,id_guia,quantidadeRetirada)
Values (ProdutosEncomenda.cod_produto,ProdutosEncomenda.cod_armazem,stockPedido);
end if;
end loop;
Close c_ProdutosEncomenda;
Exception
when ex_cod_notaEcomenda_n_existe then
raise_application_error(-20001,'Nota de encomenda inexistente'); end;
What is ProdutosEncomenda? I can only guess it is a variable of some record type. If that's the case then you should not select from it. Instead you can simply get specific field values like this:
armazem := ProdutosEncomenda.cod_armazem;
produto := ProdutosEncomenda.cod_produto;
But it would be really easier if you showed the whole code (and not as an image as a_horse_with_no_name is suggesting). It's good that you attached the errors, but I don't even know which lines they refer to
Can I convert an explicit cursor into a ref cursor? I was thinking of something like:
declare
cursor c is
select x from tab;
rc sys_refcursor;
begin
open c;
rc:=c;
close c;
end;
/
I would like to use the ref coursor as an input parameter for a procedure.
I know I can always do it like this:
OPEN rc FOR select x from tab;
But I'm in the process of refactoring some old code an I would have liked to keep the explicit cursor definitions just for the sake of clarity.
As mentioned in my comment, opening a sys_refcursor for another cursor is not allowed till Oracle 11g. As you are trying to do something which demands use of sys_refcursor, once way could be like below:
Create a type
CREATE TYPE va IS TABLE OF NUMBER;
/
Block:
DECLARE
CURSOR c
IS
SELECT employee_id FROM employee;
rc SYS_REFCURSOR;
var va;
BEGIN
OPEN c;
FETCH c BULK COLLECT INTO var;
CLOSE c;
OPEN rc FOR SELECT COLUMN_VALUE FROM TABLE (var);
END;
/
You would see here that at the end am using again a SELECT statement for ref_cursor. It's just like if you dont want to use usual way, i used an alternative way.
I want to run a procedure to force a row lock on a row, but I don't want to return a result set to the client, nor do I actually want to update anything. Below is the proc:
CREATE OR REPLACE PROCEDURE SP_LOCK_Row
(IDRow IN INTEGER)
IS
BEGIN
SELECT *
FROM TBLTable
WHERE IDRow = IDRow
FOR UPDATE;
END;
The problem is that I keep getting the error: PLS-00428: an INTO clause is expected in this SELECT statement. Is there a way for me to lock the row without actually having to return a result set back to the client? The SQL Server equivalent is:
CREATE PROCEDURE dbo.SP_LOCK_Row(
#IDRow INT)
AS
SELECT *
FROM dbo.TBLTable WITH (UPDLOCK, ROWLOCK)
WHERE IDRow = #IDRow
Tks
I don't know how smart it is to code this way but this:
CREATE OR REPLACE PROCEDURE SP_LOCK_Row
(IDRow IN INTEGER)
IS
dummy varchar2(1);
BEGIN
SELECT 'x' into dummy
FROM TBLTable
WHERE IDRow = IDRow
FOR UPDATE;
END;
should do the trick.
Ronald - http://ronr.blogspot.com
I'm trying to call an Oracle stored proc using SQL Developer. The proc outputs results using a sys_refcursor. I right click in the proc window which brings up the Run PL/SQL window. When I choose the proc I want it creates all the input params etc for me. Below is the code I'm using to try and loop through the sys_refcursor and output the results, but I'm getting an error on the 'v_rec v_Return%rowtype;' line :
ORA-06550: line 6 column 9:
PLS-00320: the declaration of the type of this expression is incomplete or malformed.
ORA-06550: line 6 column 9:
PL/SQL: Item ignored
vendor code 6550
I found the looping code on a couple of other websites and it seems to be the way to do it but it's not working for me no matter what I try. Another question - on the DBMS_OUTPUT.PUT_LINE('name = ' || v_rec.ADM) am I referencing the v_rec correctly i.e. is v_rec."column_name" the correct way??
I'm not that used to Oracle and have never used SQL plus. Any suggestions appreciated.
DECLARE
P_CAE_SEC_ID_N NUMBER;
P_PAGE_INDEX NUMBER;
P_PAGE_SIZE NUMBER;
v_Return sys_refcursor;
v_rec v_Return%rowtype;
BEGIN
P_CAE_SEC_ID_N := NULL;
P_PAGE_INDEX := 0;
P_PAGE_SIZE := 25;
CAE_FOF_SECURITY_PKG.GET_LIST_FOF_SECURITY(
P_CAE_SEC_ID_N => P_CAE_SEC_ID_N,
P_PAGE_INDEX => P_PAGE_INDEX,
P_PAGE_SIZE => P_PAGE_SIZE,
P_FOF_SEC_REFCUR => v_Return
);
-- Modify the code to output the variable
-- DBMS_OUTPUT.PUT_LINE('P_FOF_SEC_REFCUR = ');
loop
fetch v_Return into v_rec;
exit when v_Return%notfound;
DBMS_OUTPUT.PUT_LINE('name = ' || v_rec.ADM);
end loop;
END;
Your problem is here:
v_Return sys_refcursor;
v_rec v_Return%rowtype;
v_Return is a cursor variable and has no specific structure (list of columns), so v_Return%rowtype is not a valid record structure to declare v_rec. It is even possible for different calls to the procedure to return cursors with different structures.
You know what you are expecting the structure of the returned cursor to be (but Oracle doesn't) so you need to explicitly define the appropriate record structure e.g.
type t_row is record (empno number, ename varchar2(30));
v_rec t_row;
You need a strongly typed ref cursor to be able to define it as a %ROWTYPE.
Example here
#Tony Andrews thanks for this it gave me a better idea where I was going wrong. Still having problems though - here's a shortened version of my proc. It's a bit complex in that it's selecting all fields from a subquery and 2 other values:
open p_fof_sec_refcur for
SELECT *
FROM(
SELECT securities.*, rownum rnum, v_total_count
FROM
(
SELECT
CFS.CAE_SEC_ID,
CFS.FM_SEC_CODE,
...
FROM
CAEDBO.CAE_FOF_SECURITY CFS
INNER JOIN caedbo.CAE_DATA_SET_ELEMENT CDSE_STAT
ON (CDSE_STAT.DATA_SET_ELEMENT_ID = CFS.APPR_STATUS)
...
WHERE APPR_STATUS = NVL(p_appr_status, APPR_STATUS)
...
)securities
)
WHERE rnum between v_pgStart and v_pgEnd;
I explicitly defined the output structure as below to match the return fields from the proc but I'm still getting an error:
v_Return sys_refcursor;
type t_row is record (CAE_SEC_ID NUMBER,FM_SEC_CODE VARCHAR2(7),...rnum number, v_total_count number);
v_rec t_row;
The error I get is
ORA-06504: PL/SQL: Return types of Result Set variables or query do not match
ORA-06512: at line 45
I'm just wondering is the "rownum rnum, v_total_count" part tripping me up. I'm pretty sure I have all the other fields in the output structure correct as I copied them directly from the proc.