Skip to Main Content

Breadcrumb

Question and Answer

Connor McDonald

Thanks for the question, Mark.

Asked: May 12, 2020 - 6:52 pm UTC

Last updated: May 18, 2020 - 2:42 am UTC

Version: 11.2.0.4

Viewed 1000+ times

You Asked

Hello,

This query returns ORA-00910: specified length too long for its datatype. Can you please help me to understand why?


VAR SYS_B_000 NUMBER;
EXEC :SYS_B_000 := 25;

-- Returns 25 as expected
select :SYS_B_000 from dual;

-- This errors with the ORA-00914 message
select cast ('HELLO' AS VARCHAR2(:SYS_B_000)) AS couponid from dual;


This query runs fine:

VAR SYS_B_000 NUMBER;
EXEC :SYS_B_000 := 25;

select :SYS_B_000 from dual;
select cast ('HELLO' AS VARCHAR2(25)) AS couponid from dual;

and Connor said...

Its the same reason as you can't create a table as:

create table T ( x varchar2(:bind));


Even though you are doing a select statement, the *data type* definition is fixed. If you needed to do this, then you could use dynamic SQL, ie

open my_cursor for 'select cast (mycol AS VARCHAR2('||:SYS_B_000||')) AS couponid from mytable';


but if you were heading down this path, I'd recommend coming up with a small discrete of lists of sizes, eg

<30bytes would be varchar2(30)
<255 would be varchar2(255)
everything else varchar2(4000)

to keep the number of permutations small

Rating

  (2 ratings)

Is this answer out of date? If it is, please let us know via a Comment

Comments

Substitution instead of bind?

Erik van Roon, May 13, 2020 - 8:52 am UTC

Obviously it could be that the example posted is a huge simplification of the real use case, but as it is posted it looks like Mark is trying to do this inside a script, rather than in e.g. stored procedures.

If the interpretation that this is to be done in scripts is correct, then what you want can be done with substitution variables instead of bind variables:

Running this script:

prompt Create table ero_strings as my source for desired dynamic string lengths
prompt ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
create table ero_strings
(name              varchar2(20)  not null
,string_length     integer       not null
);

prompt Insert string lengths into table
prompt ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
insert into ero_strings values ('small'    ,25);
insert into ero_strings values ('medium'   ,500);
insert into ero_strings values ('large-ish',4000);
insert into ero_strings values ('large'    ,32767);
commit;

prompt List possible string lengths
prompt ~~~~~~~~~~~~~~~~~~~~~~~~~~~~
select * from ero_strings order by string_length;

prompt Retrieve string length for name='small' into a substitution variable
prompt ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-- (NOTE: in SQLcl, noprint has NO EFFECT)
column string_length noprint new_value dynamic_length

select string_length
from   ero_strings
where  name = 'small'
;

prompt Use variable for length-constrained datatype
prompt ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
select &dynamic_length  dynamic_length, cast (rpad('10' ,10 ,'>')  as varchar2(&dynamic_length)) cast_varchar   from dual;

prompt The same but with a string that is too long
prompt ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
select &dynamic_length  dynamic_length, cast (rpad('100',100,'>')  as varchar2(&dynamic_length)) cast_varchar   from dual;

prompt Cleanup
prompt ~~~~~~~
drop table ero_strings;
undef dynamic_length
column string_length clear


Will result in:

ERO@EVROCS>@var_as_datatype_length.sql
Create table ero_strings as my source for desired dynamic string lengths
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

Table created.

Insert string lengths into table
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

1 row created.


1 row created.


1 row created.


1 row created.


Commit complete.

List possible string lengths
~~~~~~~~~~~~~~~~~~~~~~~~~~~~

NAME                   STRING_LENGTH
-------------------- ---------------
small                             25
medium                           500
large-ish                       4000
large                          32767

4 rows selected.

Retrieve string length for name='small' into a substitution variable
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~




1 row selected.

Use variable for length-constrained datatype
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

 DYNAMIC_LENGTH CAST_VARCHAR
--------------- -------------------------
             25 10>>>>>>>>

1 row selected.

The same but with a string that is too long
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

 DYNAMIC_LENGTH CAST_VARCHAR
--------------- -------------------------
             25 100>>>>>>>>>>>>>>>>>>>>>>

1 row selected.

Cleanup
~~~~~~~

Table dropped.

ERO@EVROCS>

Chris Saxon
May 13, 2020 - 9:46 am UTC

Good poin Erik.

Reason for question

Mark Auguston, May 14, 2020 - 3:25 pm UTC

The reason I posted the question was I received the error from running a SQLT report on a query coming from a C++ app. The application works fine, but the SQLT report showed the error. I spent many hours trying to get the query to work with the way the SQLT report built the query with the bind variables. The example I submitted was a much simpler version of the query for which I ran the SQLT report. If you run a SQLT report on the query without the bind variable, SQLT will produce a query with bind variables.

Thanks for all of your help!!
Connor McDonald
May 18, 2020 - 2:42 am UTC

thanks for the clarification

More to Explore

PL/SQL demos

Check out more PL/SQL tutorials on our LiveSQL tool.

PL/SQL docs

PL/SQL reference manual from the Oracle documentation library