I have sp in oracle. My SP is shown below
create or replace
PROCEDURE GETMONITORING
(
v_namabarang in varchar2 default null,
v_JenisLayanan in varchar2 default null,
cv_1 IN OUT SYS_REFCURSOR
)
AS
v_where VARCHAR2(200);
v_Select VARCHAR2(200);
v_from VARCHAR2(200);
v_final VARCHAR2(200);
v_result VARCHAR2(200);
BEGIN
v_Select:='select * ';
v_from :='from permohonan ';
v_where :='where sysdate=sysdate ';
IF nvl(length(v_namabarang),0) <> 0 then
v_Where := v_Where || ' AND namabarang like ''' || v_namabarang|| '%'' ';
end if;
IF nvl(length(v_jenislayanan),0) <> 0 then
v_Where := v_Where || ' AND jenislayanan like ''' || v_jenislayanan || '%'' ';
end if;
v_final :=v_select|| v_from|| v_where;
dbms_output.put_line(v_result);
END;
I tried to exec in sqlplus by
SQL> var r refcursor;
SQL> exec getmonitoring('AC','1',:r);
SQL>print :r;
and the result is "ORA-24338": Statement handle not executed
So, how I exec my SP in sqlplus ? Thanks
The error is evident from the fact that you never OPEN the CURSOR but making a reference to the SYS_REFCURSOR as OUT parameter.
ORA-24338: statement handle not executed
Cause: A fetch or describe was attempted before executing a statement handle.
Action: Execute a
statement and then fetch or describe the data.
You need to use OPEN cursor FOR... statement:
v_final :=v_select|| v_from|| v_where;
-- open the cursor
OPEN cv_1 FOR v_final;
On a side note, while compiling PL/SQL in SQL*Plus, if you see errors, you should always use SHOW ERRORS to see the full error stack.
For example,
SQL> create or replace procedure p
2 as
3 begin
4 null
5 end;
6 /
Warning: Procedure created with compilation errors.
SQL> show errors
Errors for PROCEDURE P:
LINE/COL ERROR
-------- -----------------------------------------------------------------
5/1 PLS-00103: Encountered the symbol "END" when expecting one of the
following:
;
The symbol ";" was substituted for "END" to continue.
So, now you know the exact line number and the error message which will help you to debug and fix the error.
Related
I created a function and it uses a dynamic sql:
create function check_ref_value
(
table_name varchar2,
code_value number,
code_name varchar2
) return number is
l_query varchar2(32000 char);
l_res number;
begin
l_query := '
select sign(count(1))
into :l_res
from '|| table_name ||'
where '|| code_name ||' = :code_value
';
execute immediate l_query
using in code_value, out l_res;
return l_res;
end;
But when I try to use it I get an exception "ORA-00933: SQL command not properly ended"
What is wrong with this code?
You can use EXECUTE IMMEDIATE ... INTO ... USING ... to get the return value and DBMS_ASSERT to raise errors in the case of SQL injection attempts:
create function check_ref_value
(
table_name varchar2,
code_value number,
code_name varchar2
) return number is
l_query varchar2(32000 char);
l_res number;
begin
l_query := 'select sign(count(1))'
|| ' from ' || DBMS_ASSERT.SIMPLE_SQL_NAME(table_name)
|| ' where ' || DBMS_ASSERT.SIMPLE_SQL_NAME(code_name)
|| ' = :code_value';
execute immediate l_query INTO l_res USING code_value;
return l_res;
end;
/
Which, for the sample data:
CREATE TABLE abc (a, b, c) AS
SELECT 1, 42, 3.14159 FROM DUAL;
Then:
SELECT CHECK_REF_VALUE('abc', 42, 'b') AS chk FROM DUAL;
Outputs:
CHK
1
And:
SELECT CHECK_REF_VALUE('abc', 42, '1 = 1 OR b') AS chk FROM DUAL;
Raises the exception:
ORA-44003: invalid SQL name
ORA-06512: at "SYS.DBMS_ASSERT", line 160
ORA-06512: at "FIDDLE_UVOFONEFDEHGDQJELQJL.CHECK_REF_VALUE", line 10
As for your question:
What is wrong with this code?
Using SELECT ... INTO is only valid in an SQL statement in a PL/SQL block and when you run the statement via EXECUTE IMMEDIATE it is executed in the SQL scope and not a PL/SQL scope.
You can fix it by wrapping your dynamic code in a BEGIN .. END PL/SQL anonymous block (and reversing the order of the bind parameters in the USING clause):
create function check_ref_value
(
table_name varchar2,
code_value number,
code_name varchar2
) return number is
l_query varchar2(32000 char);
l_res number;
begin
l_query := '
BEGIN
select sign(count(1))
into :l_res
from '|| DBMS_ASSERT.SIMPLE_SQL_NAME(table_name) ||'
where '|| DBMS_ASSERT.SIMPLE_SQL_NAME(code_name) ||' = :code_value;
END;
';
execute immediate l_query
using out l_res, in code_value;
return l_res;
end;
/
(However, that is a bit more of a complicated solution that just using EXECUTE IMMEDIATE ... INTO ... USING ....)
db<>fiddle here
(Update 2019/07/23) New way to call procedure
SET SERVEROUTPUT ON
declare
variable res sys_refcursor;
begin
my_schema.SP_READ_MEMBER('11223344', '1970/01/01', res);
EXCEPTION
WHEN OTHERS
THEN DBMS_OUTPUT.put_line ('ERROR ' || SQLERRM);
end;
/
Result
Error at line 2
ORA-06550: line 2, column 16:
PLS-00103: Encountered the symbol "SYS_REFCURSOR" when expecting one of the following:
:= . ( # % ; not null range default character
The symbol ":=" was substituted for "SYS_REFCURSOR" to continue.
(Original post)
I'm not really good on Oracle's Stored Procedure, so this error confused me much time. Had read 10 more threads on this site about PLS-00103. but none of them seems helped with my error.
Here's my Stored Procedure
create or replace procedure my_schema.SP_READ_MEMBER(keywordP in varchar2, birthdayP in varchar2, resultP out sys_refcursor)
is
v_prg_name varchar2(20) := 'SP_READ_MEMBER';
sys_sql varchar2(1000);
begin
Insertlog(SYSDATE, v_prg_name, '1.0 Start');
sys_sql := sys_sql || 'select a.no, a.name, a.id_no, to_char(a.birthday, ''yyyy/MM/dd'') as birthday, ''REGISTERED'' as type, email, mobile from rep a where 1=1 ';
if keywordP is not null then
sys_sql := sys_sql || ' and (a.no=''' || keywordP || ''' or a.name=''' || keywordP || ''' or a.id_no=''' || keywordP || ''') ';
end if;
if birthdayP is not null then
sys_sql := sys_sql || ' and a.birthday=to_date(''' || birthdayP || ''', ''yyyy/MM/dd'') ';
end if;
open resultP for sys_sql;
Insertlog(SYSDATE, v_prg_name, '2.0 Finished w/o error');
exception
when others then
declare
error_time VARCHAR2(30) := RTRIM(TO_CHAR(SYSDATE, 'YYYY/MM/DD, HH24:MI:SS'));
error_code NUMBER := SQLCODE;
error_msg VARCHAR2(300) := SQLERRM;
begin
rollback;
DBMS_OUTPUT.PUT_LINE(error_time || ',' || TO_CHAR(error_code) || ',' || error_msg);
Insertlog(SYSDATE, v_prg_name, error_msg || ', 3.0 ERROR, sql:' || sys_sql);
end;
end;
/
And run it in toad, with following script :
SET SERVEROUTPUT ON
declare
res varchar2(1000);
begin
call my_schema.SP_READ_MEMBER('11223344', '1970/01/01', res);
EXCEPTION
WHEN OTHERS
THEN DBMS_OUTPUT.put_line ('ERROR ' || SQLERRM);
end;
/
This error message really confused me much hours...
Error at line 2
ORA-06550: line 4, column 8:
PLS-00103: Encountered the symbol "my_schema" when expecting one of the following:
:= . ( # % ;
The symbol ":=" was substituted for "my_schema" to continue.
Now I'm stuck here, please gives some suggestions, really need this ...
PS: Got same error message while called from c#
You have ro remove the call; for example:
SQL> begin
2 call testProc;
3 end;
4 /
call testProc;
*
ERROR at line 2:
ORA-06550: line 2, column 10:
PLS-00103: Encountered the symbol "TESTPROC" when expecting one of the
following:
:= . ( # % ;
The symbol ":=" was substituted for "TESTPROC" to continue.
SQL> begin
2 testProc;
3 end;
4 /
PL/SQL procedure successfully completed.
Also, notice that your procedure has a sys_refcursor out parameter, but you call it by passing a varchar2.
As an aside, using a varchar2 to handle dates is not a good idea; the date type would be better.
As mentioned in the previous answer, There are several mistakes in calling the procedure itself.
Your code to call the procedure should look like the following:
SET SERVEROUTPUT ON
declare
res SYS_REFCURSOR; -- Changed data type of this variable
begin
my_schema.SP_READ_MEMBER('11223344', '1970/01/01', res); -- removed 'call'
EXCEPTION
WHEN OTHERS
THEN DBMS_OUTPUT.put_line ('ERROR ' || SQLERRM);
end;
/
Cheers!!
The procedure is for cloning a table. It receives the names of the two tables in parameters, and when called it should clone the table.
CREATE OR REPLACE PROCEDURE CLONE_TABLE(
table_source VARCHAR2,
table_destination VARCHAR2)
is
begin
execute immediate 'create table ' || table_destination || 'as select* from '
|| table_source;
end;
But when i call the procedure, I receive error ORA-00922: Missing or invalid option.
BEGIN
CLONE_TABLE('example','example_new')
END
I don't realise what's the problem and how should I fix it.
Writing dynamic SQL is hard, because what should be compilation errors become runtime errors. It is therefore crucial to develop a cool eye when looking at your own code. You have to be the compiler.
It helps to assemble the statement as a variable first. That way you can display the statement in the case of error, which makes debugging easier.
CREATE OR REPLACE PROCEDURE CLONE_TABLE(
table_source VARCHAR2,
table_destination VARCHAR2)
is
stmt varchar2(32767);
begin
stmt := 'create table ' || table_destination || 'as select* from '
|| table_source;
execute immediate stmt;
exception
when others then
dbms_output.put_line(stmt);
raise;
end;
If you had done that if would have been obvious that you were missing a space in front of the as. So your executed statement was this:
create table example_newas select* from example
The space between select and * is optional, but code looks better with one.
There are only 2 problem and couple of suggestions for your code.
Missing space before as select...
Calling of procedure, use exec or call statements.
Suggestions:
Make sure to do proper error handling (so if a table doesn't exists, or if a table destination already exists, you should get proper return message.
Also separate each keyword with space as other answers suggested, like between select and *. But not doing it will not give you error.
CREATE OR REPLACE PROCEDURE CLONE_TABLE(
table_source VARCHAR2,
table_destination VARCHAR2)
is
begin
execute immediate 'create table ' || table_destination || ' as select* from '
|| table_source;
end;
EXEC CLONE_TABLE('example','example_new')
Use this:
CREATE OR REPLACE PROCEDURE CLONE_TABLE (table_source VARCHAR2,
table_destination VARCHAR2)
IS
v_sql varchar2(1000);
BEGIN
v_sql:= 'create table '
|| table_destination
|| ' as select * from '
|| table_source;
dbms_output.put_line(v_sql);
EXECUTE IMMEDIATE v_sql;
END;
The best way to handle issue like you got is to display first what you are trying to execute immediate. You get to know your fault.
There is should be one space before as select.. and in between select and * near select*....
SQL> CREATE OR REPLACE PROCEDURE CLONE_TABLE(
table_source VARCHAR2,
table_destination VARCHAR2)
is
begin
execute immediate 'create table ' || table_destination || ' as select * from ' || table_source;
end;
/ 2 3 4 5 6 7 8
Procedure created.
SQL> create table example(id number);
Table created.
SQL> exec CLONE_TABLE('example','example_new');
PL/SQL procedure successfully completed.
Following is an oracle procedure
create or replace
PROCEDURE INSERT_COMMON(
ENTITY_NAME IN VARCHAR2
, INSERT_QUERY IN varchar2
)
AS
NEW_ID NUMBER;
BEGIN
-- execute insert
DBMS_OUTPUT.PUT_LINE('INSERT_QUERY: ' || INSERT_QUERY);
-- execute IMMEDIATE INSERT_QUERY returning ID into NEW_ID;
-- above gives me a syntax error so using as below
execute IMMEDIATE INSERT_QUERY || ' returning ID into NEW_ID';
DBMS_OUTPUT.PUT_LINE('NEW_ID: ' || NEW_ID);
END INSERT_COMMON;
and Pl/SQL I am using
DECLARE
ENTITY_NAME VARCHAR2(200);
INSERT_QUERY VARCHAR2(200);
BEGIN
ENTITY_NAME := 'company';
INSERT_QUERY := 'INSERT INTO COMPANY (NAME) VALUES (''A Company 2'')';
INSERT_COMMON(ENTITY_NAME,INSERT_QUERY);
END;
This gives me following error
Error report:
ORA-00905: missing keyword
ORA-06512: at "SYSTEM.INSERT_COMMON", line 20
ORA-06512: at line 8
00905. 00000 - "missing keyword"
However, I have tested and following works fine
DECLARE
NEW_ID NUMBER;
BEGIN
INSERT INTO COMPANY (NAME) VALUES ('A Company 2') returning ID into NEW_ID;
DBMS_OUTPUT.PUT_LINE('NEW_ID: ' || NEW_ID);
END;
You need to specify a bind variable you're returning into in the dynamic sql statement, but you also then need to add the returning into <variable> clause to the execute immediate statement.
I believe (untested, since you didn't provide the statements to set up your table and associated triggers) that the following should sort your issue:
create or replace procedure insert_common (entity_name in varchar2,
insert_query in varchar2)
as
new_id number;
begin
-- execute insert
dbms_output.put_line ('INSERT_QUERY: ' || insert_query);
-- above gives me a syntax error so using as below
execute immediate insert_query || ' returning ID into :NEW_ID' returning into new_id;
dbms_output.put_line ('NEW_ID: ' || new_id);
end insert_common;
/
I met below error when I execute the following code.
Error report:
ORA-01722: invalid number
ORA-06512: at line 12
01722. 00000 - "invalid number"
Can you please help me to find out the root reason.
declare
v_str varchar2(100):='XY';
v_cnt number := 1;
v_text varchar2(100);
v_sysdate date := sysdate;
begin
v_text := 'select to_char(' || '''' || v_sysdate || '''' || ',''yyyy/mm/dd'') from dual';
dbms_output.put_line(v_text);
execute immediate v_text into v_str;
dbms_output.put_line(v_str);
end;
The problem is that you are trying to convert a char to a char as if the first one were a date. Notice that you're executing the following query:
select to_char('2014-03-14','yyyy/mm/dd') from dual
It doesn't make any sense. The "date" (2014-03-14) is actually a string and you can't treat that like if it were a date.
If you just want to cast v_sysdate to a varchar2, you could just do:
v_str := to_char(v_sysdate,'yyyy/mm/dd');
Or maybe you just were studying how dynamic SQL works...
Please, everyone test it before answer... problem with execute immediate..
------ so i think this is what you wanted..
declare
v_str varchar2(100):='XY';
v_cnt number := 1;
v_text varchar2(100);
v_sysdate date := sysdate; --
begin
v_text := 'select to_char(:x,''yyyy.mm.dd'') from dual';--:x dynamically built sql statement using IN OUT v_variable1, IN v_variable2;
dbms_output.put_line(v_text);
execute immediate v_text into v_str using in v_sysdate;
dbms_output.put_line(v_str);
end;
you can't just put variable into execute string and expect something ;) you need to define him to use in that place... v_sysdate goes into defined :x place...