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.
Related
I want to convert a string array to a date type array. But I'm not sure if my date array is correctly defined. Can't find any example of how to define or create an array of date type.
This is how I have declared my string array and date type array.
create or replace TYPE array_collection IS table OF VARCHAR2(50)
--string array is working absolutely fine so dw about that
create or replace type date_array is table of date;
--here i don't if I've defined this array correctly
my convert array procedure:
create or replace procedure convert_arr(
dat_ar in array_collection,perdate_arr out date_array)
as
begin
perdate_arr:=new date_array();
perdate_arr.extend(dat_ar.count);
for i in 1..dat_ar.count loop
perdate_arr(i):=to_date(dat_ar(i), 'yyyy-mm-dd');
end loop;
end convert_arr;
--compiles perfectly
calling anonymous block:
set serveroutput on
declare
--l_dat array_collection;
--l_darray date_array;
l_dat array_collection:=array_collection();
l_darray date_array:=date_array();
begin
l_dat := array_collection('2011-01-01','2011-04-01','2011-05-01');
--l_dat.extend(3);
-- l_dat(1):= to_date(2019-07-08);
-- l_dat(2):= to_date(2019-07-09);
-- l_dat(3):= to_date(2019-06-02);
convert_arr(dat_ar=>l_dat,perdate_arr=>l_darray);
dbms_output.put_line('Number of array:' || l_dat.count);
for i in 1..l_dat.count loop
dbms_output.put_line('Date ' || i || ':' || to_char(l_dat(i),'dd/mm/yyyy'));
end loop;
end;
this block gives me an error:
Error report -
ORA-01861: literal does not match format string
ORA-06512: at line 9
01861. 00000 - "literal does not match format string"
*Cause: Literals in the input must be the same length as literals in
the format string (with the exception of leading whitespace). If the
"FX" modifier has been toggled on, the literal must match exactly,
with no extra whitespace.
*Action: Correct the format string to match the literal.
Tried changing formats but doesn't help. Any help would be highly appreciated. Thankyou
Since l_darray is your date array, loop through it for displaying rather than l_dat
set serveroutput on
declare
--l_dat array_collection;
--l_darray date_array;
l_dat array_collection:=array_collection();
l_darray date_array:=date_array();
begin
l_dat := array_collection('2011-01-01','2011-04-01','2011-05-01');
--l_dat.extend(3);
-- l_dat(1):= to_date(2019-07-08);
-- l_dat(2):= to_date(2019-07-09);
-- l_dat(3):= to_date(2019-06-02);
convert_arr(dat_ar=>l_dat,perdate_arr=>l_darray);
dbms_output.put_line('Number of array:' || l_darray.count);
for i in 1..l_darray.count loop
dbms_output.put_line('Date ' || i || ':' || to_char(l_darray(i),'dd/mm/yyyy'));
end loop;
end;
/
Result
Number of array:3
Date 1:01/01/2011
Date 2:01/04/2011
Date 3:01/05/2011
PL/SQL procedure successfully completed.
Can you advice on a method of doing updates on clob fields in Oracle?
The query is a simple one and running it I get
ORA-01704: string literal too long:
Update table_name
Set clob_field=value2
Where column=condition1 and clob_field=value1
The scope is to update the value in a clob column with a new value.
Thanks
Is Your code part of some PLSql procedure or it is simple SQL statement? Do You pass variable "value2" as bind variable or it is quoted string inside the query? Are You on 12c or some earlier release of Oracle DB?
Generally, the most common "not obvious" issue is related to the fact that varchar2 type is limited to 4000 characters in SQL statements. If You are in PLSql procedure, the limit is 32K characters.
Can You provide code sample? The fact is that following two statements result in different behavior:
update table_name
set clob_field=value2
where column=condition1
and clob_field=value1
update table_name
set clob_field='Some very long string.....end of very long string'
where column=condition1
and clob_field='Some even longer string.....end of even longer string'
Take a look at post Error : ORA-01704: string literal too long - example how to put update in plsql block in order to achieve 32.767 character limit.
edit:
Take a look at post Working with very large text data and CLOB column, too
As you may know, it is not possible to insert more than 4k characters at one time in a clob field with Oracle Database.
A workaround to solve this issue is to split the whole string in 2 string < 4k
Example :
create table t_test (id number, texte clob);
insert into t_test (id, texte) values(1, to_clob ('value of 3999 characters') || to_clob ('value of remaining 1001 characters'));
You can use the "Lorem ipsum" to do the test :-)
Put your string value to a CLOB variable first:
declare
c clob;
s varchar2(4000);
begin
s:=rpad('x',4000,'x');
for i in 1..100 loop
c:=c||s;
end loop;
dbms_output.put_line( dbms_lob.getlength(c) );
-- length of "c" is 400000 now
update table_name set clob_field=c where id=12345;
end;
/
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;
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.
Here's the code... this isn't the complete code. I trimmed it down to where the first error occurred:
FUNCTION get (
p_sql_o OUT VARCHAR2
) RETURN VARCHAR2 AS
str_sql VARCHAR2(4000);
BEGIN
str_sql := ' SELECT * FROM ( SELECT A.*, ROWNUM RNUM FROM ( ' ||
' SELECT item_code, ' ||
' item_desc, ' ||
' monitor, ' ||
' measured, ' ||
' inventory, ' ||
' (measured - inventory) adj_amount, ' ||
' (inventory_cost * measured) measured_cost, ' ||
'inventory';
RETURN str_sql;
EXCEPTION
WHEN OTHERS THEN
RETURN NULL;
END get;
Obviously, the SQL is incomplete, but I'm not running it. I'm simply returning the SQL string, yet I still get an error:
ORA-06502: PL/SQL: numeric or value error: character string buffer too small
ORA-06512: at line 6
This is baffling. Does anyone have any clue as to why this would be the case?
Since you've said you aren't attempting to dynamically execute the SQL you're creating, the syntax and correctness of what's in there, or the length of what it might return, is clearly irrelevant. You aren't doing anything with your p_sql_o OUT parameter, so that isn't causing this problem either. That only really leaves str_sql as the culprit, and as Justin implied yesterday, it's declared as large enough within the function and the function itself compiles OK - so it looks like it has to be how it's being called that's the problem.
You mentioned it works if you remove the 'inventory', which reduced the length of that string from 201 to 192 characters, so I'm guessing you've got this set to 200 chars in the caller, something like:
declare
str_sql varchar2(200);
p_sql_o varchar2(4000);
begin
str_sql := get(p_sql_o);
end;
/
declare
*
ERROR at line 1:
ORA-06502: PL/SQL: numeric or value error: character string buffer too small
ORA-06512: at line 5
Note that the line number this is reporting is 5, not 6 as you had; it's the line in the caller that has the error, not the line the assignment happens inside the function. If I make it str_sql varchar2(250); in the caller declaration then it works (but it might as well be 4000 to match the declaration in the function).
declare
str_sql varchar2(250);
p_sql_o varchar2(4000);
begin
str_sql := get(p_sql_o);
end;
/
PL/SQL procedure successfully completed.
But p_sql_o will still be empty because you never set it. It looks like the OUT parameter is redundant. Perhaps you meant to put the SQL string into that instead, and that is already declared as big enough in the caller; but then it isn't clear what the return value would be - you probably just want to remove the OUT parameter completely, and make sure the variable in the caller that you're putting the return value into is large enough.
Have you tried just running the SQL script against the DB outside of the SP? This will help to determine if the sql syntax is correct and that you are returning what is expected. It looks like you expect to get a response that is 4000 bytes or smaller. Are you sure that is what is being returned? I don't see Where clause. Maybe you are returning multiple rows that exceed your limit? Admittedly, I'm not as familiar with stored procedures, so I could be off.
Here you are using p_sql_o as out parameter and not assigning any value inside your function.
So p_sql_o will hold the value it had previously in the code follows after calling line of this function.
As you defined str_sql can hold only 4000 char, if your concatenated string is going beyond that limit it will give character string buffer too small ORA-06512 error.
When you are concatenating the string to create a select statement, check if you are using the single quotes properly or you are missing them at all. If this is happening then while executing the dynamic select statement you may get this error ORA-06502: PL/SQL: numeric or value error: