Skip to Main Content
  • Questions
  • blank-padding VARCHAR2 in SELECT-Statements

Breadcrumb

Question and Answer

Connor McDonald

Thanks for the question, J%C3%B6rg.

Asked: December 03, 2015 - 12:24 pm UTC

Last updated: December 04, 2015 - 12:17 pm UTC

Version: 11.2.0.4

Viewed 10K+ times! This question is

You Asked


Hello

I am busy migrating a C-application from RdB (OpenVMS, usinf SQL module language) to Oracle (Linux, using embedded SQL). I now found a probleme which I have not been able to solve.

In RdB, we had a table

create table mytab(id integer, name char(10)) ;
insert into mytab values(1, 'smith') ;
insert into mytab values(2, 'smith ') ;

As datatype char does not regard trailing spaces, values 'smith' and 'smith ' in the database where regarded as equal.

As our customer wishes, we had to use VARCHAR2 instead of CHAR in the new Oracle database:

create table mytab(id integer, name char(10)) ;

Now, the values 'smith' and 'smith ' are regarded as different, but I can live with this.

What I do not understand is that in an embedded SQL statement when selecting the names, both are filled with padding spaces to the length of the host variable:

void mytab_select_name(long id, char name[11])
{
EXEC SQL
SELECT mytab.name INTO :name FROM mytab WHERE id = :id ;
}

Both calls mytab_select_name(1, name) and mytab_select_name(2, name) give me the value 'smith ' (six trailing spaces and \0) in the variable <name>. When I now write them back into the database, I have the names filled up with spaces, and when I select the entries by name I get
select * from mytab where name = 'smith' ; -> no rows found
select * from mytab where name = 'smith ' ; -> no rows found
select * from mytab where name = 'smith ' ; -> no rows found

Which would be the most efficient way to change this behaviour? I do not need trailing spaces in my values.

Ways I found:

select * from mytab where cast(name as char(10)) = 'smith' ;
select * from mytab where trim(name) = trim('smith ') ;

As I got more than 4000 embedded SQL statements, best for me where a way I could change the behaviour 'globally'.

In advance, thank you very much for your help

Best regards
Jörg



and Chris said...

I'm not following your example. The table has a char column - should it be a varchar2?

In any case, you can achieve what you want by:

- Renaming the table
- Create a view over the top of the table casting it as appropriate.

create table mytab(id integer, name varchar2(10)) ;
insert into mytab values(1, 'smith') ;
insert into mytab values(2, 'smith ') ;
commit;

select *
from   mytab
where  name = 'smith    ';

no rows selected

rename mytab to mytab_t;
create or replace view mytab as
  select id, cast(name as char(10)) name from mytab_t;

select *
from   mytab
where  name = 'smith    ';

        ID NAME     
---------- ----------
         1 smith     
         2 smith     


You'll also need to create instead of triggers on the view which do the inserts/updates:

insert into mytab (id, name) values(3, 'smith ') ;

SQL Error: ORA-01733: virtual column not allowed here

create or replace trigger trig 
instead of insert on mytab 
for each row
begin
  insert into mytab_t 
  values (:new.id, cast(:new.name as varchar2(10)));
end;
/

insert into mytab (id, name) values(3, 'smith ') ;

select * from mytab;

        ID NAME     
---------- ----------
         1 smith     
         2 smith     
         3 smith     


Rating

  (5 ratings)

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

Comments

Trailing blanks require caution

Mike, December 03, 2015 - 8:56 pm UTC

I agree that VARCHAR2 is your preferred datatype. It more closely matches your description of the legacy CHAR - and if you get into a habit of using CHAR in Oracle you will probably come to regret it.

Note (as Chris said) your example suggests you are using CHAR columns, not VARCHAR2. So you should make sure you are testing with the datatypes you really plan to use.

You may get different results comparing CHAR, VARCHAR2, and literal strings. The behavior of comparison with literal strings is particularly subtle. See http://docs.oracle.com/database/121/SQLRF/sql_elements002.htm#SQLRF51043


Explanation of my needs

J%C3%B6rg Mohren, December 04, 2015 - 10:12 am UTC

Hello

Perhaps I did not explain my problem properly. From my point of view, Oracle should either ignore trailing spaces, or return the exact value. But Oracle blank-pads values of type VARCHAR2 up to the length of the host variable when I select them via embedded SQL.

void mytab_select_name(long id, char name[11])
{
  EXEC SQL
    SELECT mytab.name INTO :name FROM mytab WHERE id = :id ;
}


No matter if there is the value 'smith' or 'smith ' in the database, the function returns 'smith ' (five additional spaces).

The idea using views could help, but represents a lot of work (more than 200 tables ...).

Any other ideas?

Best regards
Jörg
Chris Saxon
December 04, 2015 - 12:15 pm UTC

This will be happening in your client environment. There's no trailling spaces the varchar2 data type (unless you put them there yourself).

Surely you can script the move to views?

Query user_tab_cols to find all the columns of VARCHAR2. Then you can generate the rename table/create view statements from this.

Idea

J%C3%B6rg Mohren, December 04, 2015 - 10:48 am UTC

Hello

I just found something in the documentation. Would do you think, would the preprocessor option CHAR_MAP=STRING help?

Best regards
Jörg
Chris Saxon
December 04, 2015 - 12:17 pm UTC

I'm

Mike, December 04, 2015 - 11:29 am UTC

Your example showed mytab.name as a CHAR column, not VARCHAR2. You can't use a CHAR column to demonstrate VARCHAR2 behavior.

Please show: the actual DDL for the table you are querying; the INSERT statement that populated the row you are querying; the SELECT statement that queries that row; the declarations of the variables that receive the result of your query; the code that demonstrates whether there are or are not trailing spaces.

Somewhere is the above, there will be something amiss.

Error on my behalf

J%C3%B6rg Mohren, December 04, 2015 - 11:40 am UTC

Hello

The second definiton of table MYTAB (the one for Oracle) was wrong; it should have been NAME VARCHARE2(10).
The solution I found seems to work; if I use the precompiler option CHAR_MAP=STRING for compiling ESQL, my hosts variables (of C-Type char[]) are not filled with blank, but onyl \0-terminated.

Thank you for your help
Jörg

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