I am NewBie to Oracle. When I Execute Following Statement
BEGIN
EXECUTE IMMEDIATE 'SELECT * FROM DUAL;';
END;
/
I Got Error as
Error starting at line : 2 in command - BEGIN EXECUTE IMMEDIATE
'SELECT * FROM DUAL;'; END;
Error report - ORA-00911: invalid
character ORA-06512: at line 2
00911. 00000 - "invalid character"
*Cause: identifiers may not start with any ASCII character other than
letters and numbers. $#_ are also allowed after the first
character. Identifiers enclosed by doublequotes may contain
any character other than a doublequote. Alternative quotes
(q'#...#') cannot use spaces, tabs, or carriage returns as
delimiters. For all other contexts, consult the SQL Language
Reference Manual.
*Action:
The problem is the ; character in 'SELECT * FROM DUAL;'.
From documentation:
execute_immediate_statement ::=
EXECUTE_IMMEDIATE dynamic_string
{
INTO { define_variable [, define_variable ...] | record_name }
| BULK COLLECT INTO { collection_name [, collection_name ...] | :host_array_name }
}
[ USING [ IN | OUT | IN OUT ] bind_argument
[, [ IN | OUT | IN OUT ] bind_argument] ... ] [ returning_clause ] ;
... where dynamic_string is (emphasis mine):
A string literal, variable, or expression that represents a single SQL
statement or a PL/SQL block. It must be of type CHAR or VARCHAR2, not
NCHAR or NVARCHAR2.
Since it won't accept multiple statements unless you enclose them in a single PL/SQL block, the ; separator is not expected.
There's a better explanation at Using the EXECUTE IMMEDIATE Statement in PL/SQL:
When constructing a single SQL statement in a dynamic string, do not
include a semicolon (;) at the end inside the quotation mark. When
constructing a PL/SQL anonymous block, include the semicolon at the
end of each PL/SQL statement and at the end of the anonymous block;
there will be a semicolon immediately before the end of the string
literal, and another following the closing single quotation mark.
you can fix the error by removing ; from the dynamic query.
BEGIN
EXECUTE IMMEDIATE 'SELECT * FROM DUAL';
END;
/
This query is not going to return any results;
select statement in EXECUTE IMMEDIATE without into clause will be ignored.
Declare
v_variable number;--some variable
BEGIN
EXECUTE IMMEDIATE 'SELECT clmn FROM tbl' into v_variable;
END;
/
Just remove ';' from the dymanic string.Try this :
BEGIN
EXECUTE IMMEDIATE 'SELECT * FROM DUAL';
END;
Related
I get the following error message in a stored procedure that I created:
ORA-00933: SQL command not properly ended
ORA-06512: at line 11
I have tried Googling it, but could not find anything applicable as it tells my to try to eliminate any 'ORDER BY'.
declare
cursor a_tab is
select table_name
from all_tables
where owner = 'OFFERINGWORKSPACE'
and (TABLE_NAME like 'EBA_%' or TABLE_NAME = 'SURVEY_2.0');
v_tab_name varchar2(500);
begin
open a_tab;
loop
fetch a_tab into v_tab_name;
exit when a_tab%notfound;
EXECUTE IMMEDIATE 'delete ' || v_tab_name;
end Loop;
close a_tab;
open a_tab;
Loop
fetch a_tab into v_tab_name;
Exit when a_tab%notfound;
EXECUTE IMMEDIATE 'insert into ' || v_tab_name || '(select * from OFFERINGWORKSPACE.'||v_tab_name ||')';
End Loop;
Close a_tab;
End;
There is a clue in your cursor query:
... TABLE_NAME = 'SURVEY_2.0');
The period in that breaks the database object naming rules:
Nonquoted identifiers can only contain alphanumeric characters from your database character set and the underscore (_). Database links can contain periods (.) and "at" signs (#).
so that table name must be a quoted identifier. You therefore need to quote it in your statements:
EXECUTE IMMEDIATE 'delete "' || v_tab_name || '"';
and
EXECUTE IMMEDIATE 'insert into "' || v_tab_name
|| '"(select * from OFFERINGWORKSPACE."'||v_tab_name ||"')';
db<>fiddle showing the errors from those commands (simplified to one schema, and static SQL), and how adding the double quotes fixes them.
I have the following code
BEGIN
EXECUTE IMMEDIATE 'CALL name_package.name_procedure('string literal too long...')';
END;
when I run it I get the following error:
ORA-01704: string literal too long
ORA-06512: line 2
01704. 00000 - "string literal too long"
*Cause: The string literal is longer than 4000 characters.
*Action: Use a string literal of at most 4000 characters.
Longer values may only be entered using bind variables.
I have tried with a variable clob but the error persists, some idea of how to solve this issue, i am using oracle 11g
Use a bind variable:
DECLARE
str CLOB := EMPTY_CLOB();
BEGIN
-- Make a long (random) string:
FOR i IN 1 .. 10 LOOP
str := str || DBMS_RANDOM.STRING( 'a', 4000 );
END;
-- Pass it into the dynamic SQL:
EXECUTE IMMEDIATE 'CALL name_package.name_procedure( :1 )' USING str;
-- Or just call the procedure without dynamic SQL:
name_package.name_procedure( str );
END;
Unclear what you are trying to accomplish. Within a PL/SQL block you would need only reference name_package.name_procedure('string'). Assuming name_procedure is defined in the specification of name_package.
BEGIN
name_package.name_procedure('string');
END;
CLOB variable would work in place of 'string' but only if that parameter is defined as CLOB and not as VARCHAR2.
EXECUTE IMMEDIATE requires a string. Quotes within a quoted string need to be presented twice.
I'm trying to insert random generating data into table, here's code"
begin
FOR x in 1..300 LOOP
Execute immediate 'insert into emp values ('||prac_seq.nextval||','''||'name'||x||''','||trunc(dbms_random.value(1,300))||');';
end loop;
/
table emp has 3 columns - id,name,idmgr;
above query in execute immediate statement looks like:
insert into emp values (13,'name25',193);
This block did not run. When I tried to run single execute immediate statement (f.e.
begin
Execute immediate 'insert into emp values ('||prac_seq.nextval||','''||'name23'','||trunc(dbms_random.value(1,300))||');'
end;
/
ORA gives me an error:
Execute immediate 'insert into emp values
('||prac_seq.nextval||','''||'name23'','||trunc(dbms_random.value(1,300))||');';
end; Error report: ORA-00911: invalid character ORA-06512: at line 3
00911. 00000 - "invalid character"
*Cause: identifiers may not start with any ASCII character other than
letters and numbers. $#_ are also allowed after the first
character. Identifiers enclosed by doublequotes may contain
any character other than a doublequote. Alternative quotes
(q'#...#') cannot use spaces, tabs, or carriage returns as
delimiters. For all other contexts, consult the SQL Language
Reference Manual.
*Action:
And why? Commas, quotes.. everything is checked and fine.
Why are you using execute immediate for this. Try connect by level.
select prac_seq.nextval, 'name'||level, trunc(dbms_random.value(1,300)) as rnd
from dual
connect by level <= 300;
Try remove ; from your dynamic query.
Newbie to PL/SQL. I have several questions, so here's an example of what I'm trying to do.
CREATE OR REPLACE PROCEDURE "my_procedure" (
"my_inparam1" IN VARCHAR2,
"my_inparam2" IN VARCHAR2,
"my_output" OUT SYS_REFCURSOR)
AS
sql_text VARCHAR2 (10000);
BEGIN
sql_text :=
'select something
from my_table
where 1 = 1';
IF '&my_inparam1' <> 'foo'
THEN
sql_text := sql_text || ' and something = 0';
END IF;
IF '&my_inparam1' = 'foo' and '&my_inparam2' = 'bar'
THEN
sql_text := sql_text || ' and somethingelse = 1';
ELSIF '&my_inparam1' = 'foo' AND '&my_inparam2' = 'baz'
THEN
sql_text := sql_text || ' and somethingelse = 0';
END IF;
OPEN my_output FOR sql_text; --ERROR PLS-00201 Identifier 'MY_OUTPUT' must be declared
END;
So obviously I'm trying to return a query result, optionally filtered by whatever parameters I pass in. I'm at a loss as to why the offending line returns an error - in an earlier iteration, I was able to return results, but now, mysteriously, it's stopped working.
1) Is there a better way to approach this?
2) Do I have to reference the input params with the '&my_inparam' syntax?
3) If I do approach this by creating the sql text first and then opening the ref cursor, is there a shortcut for concatening the strings, like
sql_text &= ' and another_condition = 1'
?
In reverse order... no, there is no shorthand for concatenation like &=. You could use the concat() function instead, but the || method is more common, and more convenient especially if you're sticking more than two things together - nested concat() calls aren't as easy to follow. I'd stick with what you're doing.
Secondly, no, you're confusing SQL*Plus substitution variables with PL/SQL variables. Your references to '&my_inparam1' should be my_inparam1, etc; no ampersand and no quotes.
Except for some reason you've decided to make life difficult for yourself and use case-sentisive procedure and variable names, so you have to refer to "my_inparam1", in double quotes, everywhere.
That's why you're getting the message PLS-00201 Identifier 'MY_OUTPUT' must be declared. You didn't quote my_output so by default it's looking for a case-insensitive variable called MY_OUTPUT, which does not exist. It would work if you did this instead:
OPEN "my_output" FOR sql_text;
Unless you have a really really good reason, really don't do that.
CREATE OR REPLACE PROCEDURE my_procedure (
my_inparam1 IN VARCHAR2,
my_inparam2 IN VARCHAR2,
my_output OUT SYS_REFCURSOR)
AS
sql_text VARCHAR2 (10000);
BEGIN
sql_text :=
'select something
from my_table
where 1 = 1';
IF my_inparam1 <> 'foo'
THEN
sql_text := sql_text || ' and something = 0';
END IF;
...
OPEN my_output FOR sql_text;
END;
For more information, refer to the naming rules:
Every database object has a name. In a SQL statement, you represent
the name of an object with a quoted identifier or a nonquoted
identifier.
A quoted identifier begins and ends with double quotation marks (").
If you name a schema object using a quoted identifier, then you must
use the double quotation marks whenever you refer to that object.
A nonquoted identifier is not surrounded by any punctuation.
And more importantly:
Note:
Oracle does not recommend using quoted identifiers for database object names. These quoted identifiers are accepted by
SQL*Plus, but they may not be valid when using other tools that manage
database objects.
You quoted procedure name falls into this category; so do the quoted variable names. They're all identifiers and the same advice applies.
I want PLSQL to generate strings like:
COMMENT ON COLUMN TABLE.COLUMN IS 'comment from database';
My solution is:
declare
str_comment varchar2(4000);
begin
for rec in (select table_name, column_name, description from description_table)
loop
str_comment:='COMMENT ON COLUMN '||rec.table_name||'.'||rec.column_name||' IS '''||rec.description||'''; ' ;
dbms_output.put_line(str_comment);
end loop;
end;
Output is OK when it doesn't contain single qoutes in rec.description. Otherwise there is need for escape letter. How should I implement it?
OK output line (It's has escape letter to preserve single qoute):
COMMENT ON COLUMN TABLE1.COLUMN1_LV IS 'It''s secret';
NOT NOK output line because no escape letter for single quote added and doesn't compile:
COMMENT ON COLUMN TABLE1.COLUMN1_LV IS 'It's secret';
My solution is not to check if description contains single quotes. I just replace source (description) column's single quote by two single quotes before generating COMMENT ON strings and then I ROLLBACK.
Any better solution?
I do this sort stuff a fair bit (usually generating insert/update statements).
You just need to use the replace function to turn all the ' into ''. i.e. Change it to:
str_comment:='COMMENT ON COLUMN '||rec.table_name||'.'||rec.column_name
||' IS '''||REPLACE( rec.description,'''','''''')||'''; ' ;
You can use the Quote operator like
str_comment:='COMMENT ON COLUMN '||rec.table_name||'.'||rec.column_name||' IS q''[' ||rec.description|| ']'';' ;
see http://psoug.org/reference/string_func.html
Use the REPLACE function in your select.
declare
str_comment varchar2(4000);
begin
for rec in (SELECT table_name, column_name, REPLACE(description, '''', '''''')
FROM description_table)
loop
str_comment:='COMMENT ON COLUMN ' || rec.table_name || '.'
||rec.column_name|| ' IS ''' ||rec.description|| '''; ' ;
dbms_output.put_line(str_comment);
end loop;
end;
You need to use '' in the code
But Before trying it to the actual code ,
try the line which has quotes in the dual
For example:
select '''sumesh''' from dual