I am new to the vast world of oracle. What I am trying to do is, creating a stored procedure and retrieve its result.
My procedure goes as
Create or Replace Procedure usp_RotaPlateProductie_Select(
afdelingId in varchar2,
productTypeId in varchar2,
productieData out sys_refcursor)
IS
Begin
Open productieData for
Select Rotaplateproductie.Batchnummer, Cpiplusproductieorder.Productnummer,
Product.Omschrijving, Productieresultaatrtplrol.Bruto_In_Meters
From Rotaplateproductie inner join Productieresultaatrtplrol on
Rotaplateproductie.Batchnummer = Productieresultaatrtplrol.Batchnummer
inner join Cpiplusproductieorder on
Productieresultaatrtplrol.ProductieNummer = Cpiplusproductieorder.ProductNummer
inner join Product on
Cpiplusproductieorder.Productnummer = Product.Productnummer
Where Rotaplateproductie.Afdelingid = '3144' and Rotaplateproductie.producttype = 'PT005'
END;
And using the below code I am trying to execute it.
var rc REFCURSOR
EXEC usp_RotaPlateProductie_Select('3144','PT005', :rc);
While executing the above lines I am getting Ora:00900 error.
When I run the query part of the procedure, it is running fine but with procedure it gives me error.
As Shareef pointed out you're missing a semicolon on the statement inside your procedure, but it doesn't look like you're actually creating it properly. You need a / after the procedure to tell Oracle to execute the code and actually do the creation. I think it's seeing the var and exec statements as part of a single call, which is incorrect. But I'm also not sure how you're running this; if it's in SQL Developer you need to 'run script' (F5) rather than just 'run'.
Create or Replace Procedure usp_RotaPlateProductie_Select(
p_afdelingId in varchar2,
p_productTypeId in varchar2,
p_productieData out sys_refcursor)
IS
Begin
Open p_productieData for
Select Rotaplateproductie.Batchnummer, Cpiplusproductieorder.Productnummer,
Product.Omschrijving, Productieresultaatrtplrol.Bruto_In_Meters
From Rotaplateproductie
inner join Productieresultaatrtplrol on
Rotaplateproductie.Batchnummer = Productieresultaatrtplrol.Batchnummer
inner join Cpiplusproductieorder on
Productieresultaatrtplrol.ProductieNummer = Cpiplusproductieorder.ProductNummer
inner join Product on
Cpiplusproductieorder.Productnummer = Product.Productnummer
Where Rotaplateproductie.Afdelingid = p_afdelingId
and Rotaplateproductie.producttype = p_productTypeId;
END;
/
var rc REFCURSOR
EXEC usp_RotaPlateProductie_Select('3144','PT005', :rc);
print :rc
I've switched to use the IN parameters, and I've taken the liberty of changing the names so you can distinguish between parameters and column names; they were the same which can cause confusion.
You might also find it useful to alias your tables; no functional difference but maybe easier to read:
Create or Replace Procedure usp_RotaPlateProductie_Select(
p_afdelingId in varchar2,
p_productTypeId in varchar2,
p_productieData out sys_refcursor)
IS
Begin
Open p_productieData for
Select rp.Batchnummer, cppo.Productnummer,
p.Omschrijving, pra.Bruto_In_Meters
From Rotaplateproductie rp
inner join Productieresultaatrtplrol par
on rp.Batchnummer = pra.Batchnummer
inner join Cpiplusproductieorder cppo
on pra.ProductieNummer = cppo.ProductNummer
inner join Product p
on cppo.Productnummer = p.Productnummer
Where rp.Afdelingid = p_afdelingId
and rp.producttype = p_productTypeId;
END;
/
If you get a message that the procedure compiled with warnings, do 'show errors' to get the details.
did you run the code
Select Rotaplateproductie.Batchnummer, Cpiplusproductieorder.Productnummer,
Product.Omschrijving, Productieresultaatrtplrol.Bruto_In_Meters
From Rotaplateproductie inner join Productieresultaatrtplrol on
Rotaplateproductie.Batchnummer = Productieresultaatrtplrol.Batchnummer
inner join Cpiplusproductieorder on
Productieresultaatrtplrol.ProductieNummer = Cpiplusproductieorder.ProductNummer
inner join Product on
Cpiplusproductieorder.Productnummer = Product.Productnummer
Where Rotaplateproductie.Afdelingid = '3144' and Rotaplateproductie.producttype = 'PT005'
i it works please reply
i think you miss semicolon in the end
;
#Mavrik edited
After adding semicolon in the end of the query, the procedure is
created properly. thanks but it is still returning the same error code
when I tried to execute it using the below code
var rc REFCURSOR EXEC usp_RotaPlateProductie_Select('3144','PT005',
:rc);
UPDATE 1:
if you have ora 00900 it may be because of
Oracle/PLSQL: ORA-00900 Error
Related
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;
[EDIT]Editing the code to reflect changes coming from comments
I have a problem with one of the stored procedures I'm trying to create in an Oracle database.
The goal is to update every table which has an indiv column.
CREATE OR REPLACE PROCEDURE sp_majUserOnAllK (lastU IN VARCHAR2, newU IN VARCHAR2)
AS
BEGIN
FOR item IN (
select table_name , owner
from all_tab_columns
where column_name = 'INDIV' AND OWNER ='K'
)
LOOP
EXECUTE IMMEDIATE 'UPDATE K.' || item.table_name || ' SET indiv = :newValue WHERE indiv = :oldValue' USING newU, lastU;
END LOOP;
END sp_majUserOnAllK;
exec sp_majUserOnAllK( 'hum','hum');
Problem is, when I try to execute the stored procedure, I got an error message with no detail at all ('non valid SQL').
I tried taking the code out of the stored procedure. And there, it works. Only the beginning is changing to :
DECLARE
newU NVARCHAR2(50);
lastU NVARCHAR2(50);
req VARCHAR2(100);
CURSOR ctable IS
select table_name , owner from all_tab_columns where column_name = 'INDIV' AND OWNER ='KEXPLOIT';
BEGIN
newU := 'hum';
lastU := 'hum';
FOR item IN ctable
....
Like that, it works perfectly and does exactly what it is supposed to do.
As the only difference is the assignation of the variable, I think I may have a problem with my procedure declaration but I can't find a solution. The compilation is ok.
Any idea ?
Your procedure's syntax is not correct. Try this.
CREATE OR REPLACE PROCEDURE sp_majUserOnAllK (lastU IN VARCHAR2, newU IN VARCHAR2)
IS
req VARCHAR2(100);
BEGIN
FOR item IN (select table_name , owner from all_tab_columns where column_name = 'INDIV' AND OWNER ='K')
LOOP
req := 'UPDATE K.' || item.table_name || ' SET indiv = :newValue WHERE indiv = :oldValue';
EXECUTE IMMEDIATE req USING newU, lastU;
END LOOP;
-- return 1; -- note: procedures do not return values
END;
/
A five-second Google search on "dbeaver exec command" brought this up among the first few hits:
https://github.com/dbeaver/dbeaver/issues/749
In it, we learn that EXEC is not supported by dbeaver.
EXEC is an SQL*Plus command. It is not Oracle SQL, and it is not PL/SQL. SQL*Plus is a shell program of sorts for interacting with Oracle databases; it has its own language, distinct from SQL and PL/SQL.
SQL Developer and Toad (and perhaps other similar programs) support (most of) SQL*Plus, but apparently dbeaver (with which I am not familiar) does not.
The link I copied above suggests using the CALL command instead. See the link for examples.
As an aside, when we use EXEC in SQL*Plus and SQL Developer, there is no semicolon at the end of the procedure call. Adding an unnecessary semicolon, however, does not throw an error (SQL*Plus is, apparently, smart enough to simply ignore it).
I am working on a project and there is a need to write stored procedure instead of SQL query. I have never done this before and I tried now by converting the written sql to a procedure. However, I couldn't get this error free and working. Any suggestions from you folks is very helpful in fixing this..
SQL:
create or replace
PROCEDURE MS_TST_PROC AS
BEGIN
DECLARE
l_organization varchar2(40);
l_framework varchar2(10);
l_sub_category_code varchar2(20);
l_sub_category varchar2(20);
l_TST_function varchar2(20);
l_questionnaire_name varchar2(20);
l_responded_on varchar2(20);
l_overall_score number(10);
l_target_score number(10);
l_maturity number(10,2);
l_full_name varchar2(20);
cursor c_get_details
is
select
ts.organization_name,
q.framework,
q.sub_category_code,
q.sub_category,
tst.tst_function,
q.questionnaire_name,
resp.responded_on ,
resp.overall_score,
ts.target_score,
Round((resp.overall_score / ts.target_score)*100,2) as Maturity,
users.first_name || ' ' || users.last_name as full_name
into
l_organization,
l_framework,
l_sub_category_code,
l_sub_category,
l_tst_function,
l_questionnaire_name,
l_responded_on,
l_overall_score,
l_target_score,
l_maturity,
l_full_name
from MS_CMM_QUESTIONNAIRE q
INNER JOIN MS_CMM_TARGET_SCORE ts
on q.sub_category_code = ts.sub_category_code
INNER JOIN MS_CMM_CSF_FUNCTIONS tst
on tst.sub_category_code = q.sub_category_code
INNER JOIN MS_QSM_QUESTIONNAIRE qsm
on q.QUESTIONNAIRE_NAME = qsm.QUE_NAME
INNER JOIN MS_QSM_QUESTNR_RESP resp
on resp.QUESTIONNAIRE_ID = qsm.QUE_ID
and resp.applies_to_object = ts.organization_name
INNER JOIN SI_USERS_T users
on users.user_name = resp.respondent;
END MS_TST_PROC;
and compilation error says:
Error(60,1): PLS-00103: Encountered the symbol "END" when expecting one of the following: begin function pragma procedure subtype type <an identifier> <a double-quoted delimited-identifier> current cursor delete exists prior
There are a couple of issues:
You have a DECLARE statement without a subsequent BEGIN or END statement.
You have a CURSOR with an INTO clause; they cannot both be there. If the query returns a single row then just use SELECT ... INTO ... (see below), otherise, if you have multiple rows you need to process then you could use a cursor loop.
Also, it is much easier to read (and to find unmatched DECLARE/BEGIN/END statements) if you format your code and maintain proper levels of indentation.
Something like this:
CREATE PROCEDURE MS_TST_PROC
AS
l_organization MS_CMM_TARGET_SCORE.ORGANIZATION%TYPE;
l_framework MS_CMM_QUESTIONNAIRE.FRAMEWORK%TYPE;
l_sub_category_code MS_CMM_QUESTIONNAIRE.SUB_CATEGORY_CODE%TYPE;
l_sub_category MS_CMM_QUESTIONNAIRE.SUB_CATEGORY%TYPE;
l_TST_function MS_CMM_CSF_FUNCTIONS.TST_FUNCTION%TYPE;
l_questionnaire_name MS_CMM_QUESTIONNAIRE.QUESTIONNAIRE_NAME%TYPE;
l_responded_on MS_QSM_QUESTNR_RESP.RESPONDED_ON%TYPE;
l_overall_score MS_QSM_QUESTNR_RESP.OVERALL_SCORE%TYPE;
l_target_score MS_CMM_TARGET_SCORE.TARGET_SCORE%TYPE;
l_maturity number(10,2);
l_full_name varchar2(20);
BEGIN
SELECT ts.organization_name,
q.framework,
q.sub_category_code,
q.sub_category,
tst.tst_function,
q.questionnaire_name,
resp.responded_on,
resp.overall_score,
ts.target_score,
Round((resp.overall_score / ts.target_score)*100,2),
users.first_name || ' ' || users.last_name
INTO l_organization,
l_framework,
l_sub_category_code,
l_sub_category,
l_tst_function,
l_questionnaire_name,
l_responded_on,
l_overall_score,
l_target_score,
l_maturity,
l_full_name
FROM MS_CMM_QUESTIONNAIRE q
INNER JOIN MS_CMM_TARGET_SCORE ts
on q.sub_category_code = ts.sub_category_code
INNER JOIN MS_CMM_CSF_FUNCTIONS tst
on tst.sub_category_code = q.sub_category_code
INNER JOIN MS_QSM_QUESTIONNAIRE qsm
on q.QUESTIONNAIRE_NAME = qsm.QUE_NAME
INNER JOIN MS_QSM_QUESTNR_RESP resp
on resp.QUESTIONNAIRE_ID = qsm.QUE_ID
and resp.applies_to_object = ts.organization_name
INNER JOIN SI_USERS_T users
on users.user_name = resp.respondent;
-- Do something with the values.
END MS_TST_PROC;
/
I've got the following existing procedure:
create or replace
PROCEDURE pmm$AppUser_GetApprover_KFGZ7Q(
ReleaseRequestID INT )
AS
RefCursor SYS_REFCURSOR;
BEGIN
OPEN RefCursor FOR
SELECT
U.*
FROM pmm$PmmReleaseRequest R
INNER JOIN dbo$ManagedEntity ME
ON ME.ManagedEntityID = R.ManagedSystemID
INNER JOIN dbo$SmartRuleAssetCache SRC
ON SRC.AssetID = ME.AssetID
INNER JOIN dbo$UserGroup_SmartRule_Role GSR
ON GSR.SmartRuleId = SRC.SmartRuleId
AND GSR.RoleId IN (2,3)
INNER JOIN dbo$AppUser_UserGroup UG
ON UG.GroupID = GSR.UserGroupId
AND UG.UserID <> R.UserID
INNER JOIN dbo$AppUser U ON UG.UserID = U.UserID
WHERE R.ReleaseRequestID = ReleaseRequestID;
DBMS_SQL.RETURN_RESULT(RefCursor);
END;
I would like to call this from a Trigger and query the Cursor returned using some Where clauses to further refine the results.
Most ideally I would like to put the records in a temporary table.
I can't seem to find any documentation on the best way to do this.
Thanks in advance.
Not directly, no.
A SYS_REFCURSOR is a pointer to a result-- the only thing you can do
with that is to fetch the data. You can't modify the result set. However the best
way workaround for this is to put the data into some king of Temp
table( most preferred is GTT Global temporary table) and then utilize
it to do all the validations in Trigger.
Hope below snippet is useful for you.
CREATE OR REPLACE PROCEDURE test_cur(
p_out OUT sys_refcursor )
AS
BEGIN
OPEN p_out FOR SELECT LEVEL FROM DUAL CONNECT BY LEVEL < 15;
-- Here dummy tab can be any temp table or GTT
INSERT INTO DUMMY_TAB
SELECT LEVEL FROM DUAL CONNECT BY LEVEL < 15;
END;
CREATE OR REPLACE TRIGGER <Trigger_name>
AFTER INSERT OR UPDATE ON <TYABLE_NAME>
FOR EACH ROW
DECLARE
--<variable declarations>
BEGIN
dbms_output.put_line('Your code for data Manipulations');
--SELECT FROM GTT/ Temp table and all the manipulations required
END;
I have created a procedure using the following code using iSQL Plus on Firefox. The procedure compiles successfully.
create or replace procedure get_staff (
product_no in varchar2,
o_cursor out sys_refcursor)
is
begin
open o_cursor for
'select sr.name, sr.bonus from sales_staff sr inner join product p on p.sales_staff_id = sr.staff_id where product_no = ' || product_no ;
end;
I am trying to call this procedure using the following code
var rc refcursor
exec get_staff('A56',:rc)
print rc
I get the following error.
ERROR at line 1:
ORA-00904: "A56": invalid identifier
ORA-06512: at "AA2850.GET_STAFF", line 6
ORA-06512: at line 1
ERROR:
ORA-24338: statement handle not executed
SP2-0625: Error printing variable "rc"
in the case you have, there's no need for dynamic sql:
open o_cursor for
select sr.name, sr.bonus
from sales_staff sr
inner join product p
on p.sales_staff_id = sr.staff_id
where p.product_no = product_no;
if you were using dynamic SQL then ideally you would in most cases want to bind:
open o_cursor for
'select sr.name, sr.bonus
from sales_staff sr
inner join product p
on p.sales_staff_id = sr.staff_id
where p.product_no = :b1' using product_no;
failing that (edge cases, sometimes you want to avoid bind variables for skewed data), varchar2s need enclosing in quotes:
open o_cursor for
'select sr.name, sr.bonus
from sales_staff sr
inner join product p
on p.sales_staff_id = sr.staff_id
where p.product_no = ''' ||product_no||'''';
but you should escape single quotes and validate that product_no has no semi colons etc (i.e. careful of SQL injection)