The procedure uses the previous function to display the list of the products: num, designation and mention on the application.
SET SERVEROUTPUT ON;
CREATE OR REPLACE FUNCTION STORE(num_produit IN INTEGER) RETURN VARCHAR AS
N INTEGER := 0;
incre INTEGER := 0;
BEGIN
SELECT SUM(qte) INTO N FROM Ligne_Fact WHERE num_produit = produit;
IF N > 15 THEN
RETURN 'fort';
ELSIF N > 11 THEN
RETURN 'moyen';
END IF;
RETURN 'faible';
END;
/
CREATE OR REPLACE PROCEDURE SHOW_PRODUITS IS
SOME_VAR VARCHAR2(256);
BEGIN
SELECT num, designation, STORE(num) INTO SOME_VAR FROM Produit;
dbms_output.enable();
dbms_output.put_line('result : '|| SOME_VAR);
END;
/
BEGIN
SHOW_PRODUITS;
END;
/
I am sure that all the tables are filled with some dummy data, but I am getting the following error:
Function STOCKER compiled
Procedure AFFICHER_PRODUITS compiled
LINE/COL ERROR
--------- -------------------------------------------------------------
4/4 PL/SQL: SQL Statement ignored
4/56 PL/SQL: ORA-00947: not enough values
Errors: check compiler log
Error starting at line : 28 in command -
BEGIN
AFFICHER_PRODUITS;
END;
Error report -
ORA-06550: line 2, column 5:
PLS-00905: object SYSTEM.SHOW_PRODUITS is invalid
ORA-06550: line 2, column 5:
PL/SQL: Statement ignored
06550. 00000 - "line %s, column %s:\n%s"
*Cause: Usually a PL/SQL compilation error.
The first major mistake you've made is to create your objects in SYSTEM schema. It, just like SYS, are special and should be used only for system maintenance. Create your own user and do whatever you're doing there.
As of your question: select returns 3 values, but you're trying to put them into a single some_var variable. That won't work. Either add another local variables (for num and designation), or remove these columns from the select:
CREATE OR REPLACE PROCEDURE SHOW_PRODUITS IS
SOME_VAR VARCHAR2(256);
BEGIN
SELECT STORE(num) INTO SOME_VAR FROM Produit; --> here
dbms_output.enable();
dbms_output.put_line('result : '|| SOME_VAR);
END;
/
Code, as you put it, presumes that produit contains a single record (it can't be empty nor it can have 2 or more rows because you'll get various errors).
Maybe you wanted to access all rows; in that case, consider using a loop, e.g.
CREATE OR REPLACE PROCEDURE SHOW_PRODUITS IS
SOME_VAR VARCHAR2(256);
BEGIN
FOR cur_r IN (SELECT num, designation, STORE(num) some_var FROM Produit) LOOP
dbms_output.put_line(cur_r.num ||', '|| cur_r.designation ||', result : '|| cur_r.some_var);
END LOOP;
END;
/
Then
set serveroutput on
BEGIN
SHOW_PRODUITS;
END;
/
You are trying to compile some stored routine which calls another stored routine named AFFICHER_PRODUITS and that routine calls SHOW_PRODUITS but SHOW_PRODUITS does not compile, hence the error. (By the way, it is recommended not to create your own stored routines in the SYSTEM schema.)
SHOW_PRODUITS does not compile because of this line:
SELECT num, designation, STORE(num) INTO SOME_VAR FROM Produit;
It appears that you want to get the query results as a string. In order to do that, you need to concatenate the column values, i.e.
SELECT num || designation || STORE(num) INTO SOME_VAR FROM Produit;
Of-course if all you want to do is display the query results, using DBMS_OUTPUT, you can declare a separate variable for each column.
CREATE OR REPLACE PROCEDURE SHOW_PRODUITS IS
SOME_NUM Produit.num%type;
SOME_DES Produit.designation%type;
SOME_VAR VARCHAR2(6);
BEGIN
SELECT num
,designation
,STORE(num)
INTO SOME_NUM
,SOME_DES
,SOME_VAR
FROM Produit;
dbms_output.enable();
dbms_output.put_line('result : ' || SOME_NUM || SOME_DES || SOME_VAR);
END;
Note that if the query returns more than one row, you will [probably] need to use a cursor.
CREATE OR REPLACE PROCEDURE SHOW_PRODUITS IS
SOME_NUM Produit.num%type;
SOME_DES Produit.designation%type;
SOME_VAR VARCHAR2(6);
--
CURSOR c1 IS
SELECT num, designation, STORE(num) FROM Produit;
BEGIN
OPEN c1;
LOOP
FETCH c1 INTO SOME_NUM, SOME_DES, SOME_VAR;
EXIT WHEN c1%NOTFOUND;
dbms_output.put_line('result : ' || SOME_NUM || SOME_DES || SOME_VAR);
END LOOP;
CLOSE c1;
END;
Related
create sequence s1 ;
declare
v_value number;
v_sql_stmt varchar2(4000);
v_seq_name varchar2(30);
BEGIN
v_seq_name:='S1'; -- **this is dynamic and the sequence will be passed in the proc as input parameter at runtime**
v_sql_stmt:= 'select :v_seq_name'||'.nextval from dual' ;
EXECUTE IMMEDIATE v_sql_stmt INTO v_value USING v_seq_name ;
--**below is working but I dont want to do in this way because of sql injection issue, let me know how to fix the above**
--EXECUTE IMMEDIATE 'select ' || v_seq_name || '.nextval from dual' INTO v_value;
dbms_output.put_line(v_value);
end;
/
the above code is throwing error, please help to fix.
If you run the commented code then it will run but I dont want to use || in execute immediate. I want to use colon : only.
the sequence name will be passed at run time. The above code will be converted to a proc later.
I understand your concern about SQL injection. To my knowledge, table/column/sequence names cannot be specified with bind variables. However, you could do a simple check before executing the unsafe code:
CREATE SEQUENCE s1;
CREATE SEQUENCE s2;
CREATE OR REPLACE FUNCTION p(seq_name VARCHAR2) RETURN NUMBER AS
v_value number;
v_sql_stmt varchar2(4000);
v_seq_name varchar2(128 BYTE);
BEGIN
v_seq_name:= DBMS_ASSERT.SIMPLE_SQL_NAME(seq_name);
v_sql_stmt:= 'select '||v_seq_name||'.nextval from dual';
EXECUTE IMMEDIATE v_sql_stmt INTO v_value;
RETURN v_value;
END p;
/
If a valid name is used, everything works as expected:
select p('s1') from dual;
1
select p('s2') from dual;
2
However, if seq_name is not a valid Oracle name, DBMS_ASSERT throws an exception:
select p('1; DROP TABLE x') from dual;
ORA-44003: invalid SQL name
ORA-06512: at "SYS.DBMS_ASSERT", line 215
ORA-06512: at "WFL.P", line 6
44003. 0000 - "invalid SQL name"
Im a learning plsql and im trying to create procedure and calling procedure inside another procedure and i can get desired output. But when i tried to create procedure inside another procedure instead of calling another procedure, im getting the below error
"23/1 PLS-00103: Encountered the symbol "PROCEDURE" when expecting one of the following: ( begin case declare end exception exit for goto if loop mod null pragma raise return select update while with << continue close current delete fetch lock insert open rollback savepoint set sql execute commit forall merge pipe purge The symbol "declare" was substituted for "PROCEDURE" to continue.
23/18 PLS-00103: Encountered the symbol "." when expecting one of the following: in out ... long double ref char time timestamp interval date binary national character nchar
Errors: check compiler log
"
CREATE OR REPLACE PROCEDURE pro (
empn NUMBER,
emp OUT emp5%rowtype
) IS
salar number;
BEGIN
SELECT
a.*
INTO emp
FROM
emp5 a
WHERE
a.empno = empn;
dbms_output.put_line('The hire date is'
|| ' '
|| emp.hiredate);
dbms_output.put_line('Name is'
|| ' '
|| emp.ename);
procedure p44(emp.hiredate in date,emp.ename varchar,sal out number) IS
salar NUMBER;
BEGIN
SELECT
e.sal
INTO salar
FROM
emp5 e
WHERE
e.hiredate = hire
AND e.ename = enamee;
dbms_output.put_line('salary of the employee'
|| ' '
|| enamee
|| 'is '
|| salar);
END p43;
/
If i give empno number as input to procedure pro, i need output with employees hiredate,employee's name and employee's salary like the below one
The hire date is 20-FEB-81
Name is ALLEN
salary of the employee ALLEN is 1600
A procedure is a single program unit with the structure of:
create or replace procedure p43 () is
...
begin
…
end;
/
Your code has two instances of PROCEDURE and that's what the compiler is complaining about.
If you want two separate procedures you need two separate CREATE statements:
create or replace procedure p43 () is
...
begin
…
end p43;
/
create or replace procedure p44 () is
...
begin
…
end p44;
/
But if what you want is P44 as a private procedure only accessible within the context of P43 you can do that, by defining the procedure in the declaration section after any variable declarations:
create or replace procedure p43 () is
…
procedure p44 () is
...
begin
…
end p44;
begin
…
p44(…);
end p43;
/
Also this is not how we declare parameters.
procedure p44(emp.hiredate in date,emp.ename varchar,sal out number) IS
Give them unique names, say by prefixing them with p_, and if you like use the table column datatype. Something like this:
procedure p44(p_hiredate in emp.hiredate%type
,p_ename in emp.ename%type
,p_sal out emp.sal%type) IS
Giving parameters a distinct name prevents scope confusion when using parameters in SQL statements:
You can not create procedure within procedure.
Procedure is a single object and must be created alone. You can call one procedure from another.
You can use package to create multiple procedures inside single package but in that case also, procedure must be created standalone.
-- procedure must be created standalone
Create or replace procedure p44
As
Begin
-- code
End p44;
/
Create or replace procedure pro
As
Begin
P44; -- call to existing procedure
-- code
End pro;
/
So your case will go like this:
procedure p44(hiredate in date,ename varchar,sal out number) IS
salar NUMBER;
BEGIN
SELECT
e.sal
INTO salar
FROM
emp5 e
WHERE
e.hiredate = hire
AND e.ename = ename;
dbms_output.put_line('salary of the employee'
|| ' '
|| ename
|| 'is '
|| salar);
END p44;
/
CREATE OR REPLACE PROCEDURE pro (
empn NUMBER,
emp OUT emp5%rowtype
) IS
salar number;
BEGIN
SELECT
a.*
INTO emp
FROM
emp5 a
WHERE
a.empno = empn;
dbms_output.put_line('The hire date is'
|| ' '
|| emp.hiredate);
dbms_output.put_line('Name is'
|| ' '
|| emp.ename);
P44(emp.hiredate, emp.ename, salr):
END pro;
/
Cheers!!
I have procedure with params:
procedure GetReceipt(iPaymentID in number
,oReceipt out sys_refcursor
,oReceiptItems out sys_refcursor);
I try to run this my anonymous block:
SET serveroutput on;
DECLARE
oReceipt sys_refcursor;
oReceiptItems sys_refcursor;
BEGIN
API.MOD.GetReceipt(4209735, oReceipt, oReceiptItems);
dbms_output.put_line('oReceipt: ' || oReceipt);
dbms_output.put_line('oReceiptItems: ' || oReceiptItems);
END;
I get this error:
Error report:
ORA-06550: Строка 6, столбец 24:
PLS-00306: wrong number or types of arguments in call to '||'
ORA-06550: Строка 6, столбец 3:
PL/SQL: Statement ignored
ORA-06550: Строка 7, столбец 24:
PLS-00306: wrong number or types of arguments in call to '||'
ORA-06550: Строка 7, столбец 3:
PL/SQL: Statement ignored
06550. 00000 - "line %s, column %s:\n%s"
*Cause: Usually a PL/SQL compilation error.
*Action:
How call this procedure? Where my mistake?
You can use bind variables to store the cursors and PRINT to print them:
VARIABLE receipt REFCURSOR;
VARIABLE receiptitems REFCURSOR;
BEGIN
API.MOD.GetReceipt(4209735, :receipt, :receiptitems);
END;
/
PRINT receipt;
PRINT receiptitems;
Where my mistake?
A cursor is a named pointer to a private SQL area that stores information for processing a specific query. It does not make sense to concatenate a pointer to something internal to the database with a string.
If you want to display the values in your PL/SQL block then you will need to loop through each record of the cursor and get the individual column values for that record and then use DBMS_OUTPUT to display them:
SET serveroutput on;
DECLARE
oReceipt sys_refcursor;
oReceiptItems sys_refcursor;
col1 RECEIPT_TABLE.COL1%TYPE; -- Same data type as COL1 of the RECEIPT_TABLE table
col2 RECEIPT_TABLE.COL2%TYPE; -- Same data type as COL2 of the RECEIPT_TABLE table
col3 RECEIPT_TABLE.COL3%TYPE; -- Same data type as COL3 of the RECEIPT_TABLE table
rec RECEIPT_ITEMS_TABLE%ROWTYPE; -- Assumes the cursor is returning all the columns from
-- the RECEIPT_ITEMS_TABLE table
BEGIN
API.MOD.GetReceipt(4209735, oReceipt, oReceiptItems);
dbms_output.put_line('oReceipt:');
LOOP
FETCH oReceipt INTO col1, col2, col3; -- Store the values from the current record
EXIT WHEN oReceipt%NOTFOUND; -- Stop if the end of the cursor has been reached
DBMS_OUTPUT.PUT_LINE( col1 || ' ' || col2 || ' ' || col3 );
-- Output the values
END LOOP;
dbms_output.put_line('oReceiptItems:');
LOOP
FETCH oReceiptItems INTO rec; -- Fetch the current row into a record
EXIT WHEN oReceipt%NOTFOUND;
DBMS_OUTPUT.PUT_LINE( rec.colA || ' ' || rec.colB || ' ' || rec.colC );
END LOOP;
END;
/
sys_refcursor returns record set, may not be just a column.
So, you can not message it as a classical string with dbms_output.put_line. There should exists some columns(sub-components) of this argument in your routine like oReceiptItems.col_a or oReceiptItems.col_b so that you could message by these columns as strings with dbms_output.put_line.
I have created a procedure and it requires Dynamic SQL block.
Procedure is as below which complies correctly but when I try to run it , it gives the below error.
I have tried to use cast() for all the variable which are used here. But this does not help.
Also, I am trying to run this procedure on Oracle using SQL - Developer tool.
Once the dynamic SQL is stored in sqlquery variable I would try and run the dynamic query and display its results!
**Output**
*Connecting to the database XXX.
ORA-06502: PL/SQL: numeric or value error: character to number conversion error
ORA-06512: at "XXX.PROCEDURE2", line 28
ORA-06512: at line 6
Who are you ?
Process exited.
Disconnecting from the database XXX.*
Procedure
*create or replace PROCEDURE PROCEDURE2 (var_owner IN dba_tab_cols.owner%TYPE) AS
CURSOR col_ident IS
select col1_name,col2,col3,col4,nullable,'_NM' as s_type
from table_name
where col2 in var_owner
and col3 like 'exp%%'
and col4 like 'exp2%';
sample_record col_ident%ROWTYPE;
BEGIN
OPEN col_ident;
LOOP
FETCH col_ident INTO sample_record;
DECLARE
col_nm VARCHAR2(30);
tab_nm VARCHAR2(30);
schema_nm VARCHAR2(30);
--a1 VARCHAR2(30);
sqlquery VARCHAR2(400);
BEGIN
col_nm := sample_record.col2;
tab_nm := sample_record.col3;
schema_nm := sample_record.col1_name;
IF sample_record.col4 = 'VARCHAR2' THEN
DBMS_OUTPUT.PUT_LINE('Who are you ? ');
sqlquery:= ('select distinct ' +col_nm+ 'from' + schema_nm+'.'+tab_nm + 'where rownum < 1');
DBMS_OUTPUT.PUT_LINE('Do you know me ');
END IF;
EXIT WHEN col_ident%NOTFOUND;
DBMS_OUTPUT.PUT_LINE(sample_record.col1_name||','||sample_record.col3
||','||sample_record.col2||','||sample_record.col4||','||
sample_record.col5||','||sample_record.nullable||','||
sample_record.s_type);
END;
END LOOP;
--Close CURSOR col_ident
CLOSE col_ident;
END PROCEDURE2;*
I need to generate the column name dynamically in loop and access the column in oracle table using PLSQL. How do I do that?
DECLARE
varValue VARCHAR(20);
CURSOR c IS
SELECT * FROM TEST1;
BEGIN
FOR i IN c LOOP
FOR j IN 1..5
LOOP
EXECUTE IMMEDIATE 'SELECT ''NAME1'||to_Char(j)||''' from dual' INTO varValue;
dbms_output.put_line(j);
dbms_output.put_line(i.varValue);
END LOOP;
END LOOP;
END;
Actual issue is, I need to acccess the cell values of each row (i) given by cursor (c) like i.name11, i.name12....i.name1100. The logic to be deployed in each cell is same. So i need the column name used here i.e. name11 to be generated dynamically. That is alread done and stored to a variable varValue. Now how can i access the cells i.varValue such that var value is generated in the loop.
The error is as follows:
ORA-06550: line 14, column 34:
PLS-00302: component 'VARVALUE' must be declared
ORA-06550: line 14, column 11:
PL/SQL: Statement ignored
DECLARE
varValue VARCHAR(20);
CURSOR c IS
SELECT * FROM TEST1;
BEGIN
FOR i IN c LOOP
FOR j IN 1..5
LOOP
EXECUTE IMMEDIATE 'SELECT ''NAME1'||to_Char(j)||''' from dual' INTO varValue;
dbms_output.put_line(j);
dbms_output.put_line('NAME1'||to_Char(j)||' : '||varValue);
END LOOP;
END LOOP;
END;