Reputation: 11
I have the following case:
Sample code:
create table abc(aa char(10));
insert into abc values('ABC');
--ABC will be padded with 7 blank spaces
Issue:
Select * from abc where aa in ('ABC');
--This above statement returns one row with value ABC
Declare
v_temp varchar2(10);
v_aa varchar2(10) := 'ABC';
Begin
select aa into v_temp from abc where aa in (v_aa);
dbms_output.put_line(v_temp);
end;
--The above pl/sql block one execution prints nothing but if i replace the select inside that block with "select aa into v_temp from abc where aa in ('ABC');" the value will be printed.
Please advice me on the behaviour.
Upvotes: 1
Views: 4044
Reputation: 150
If a VARCHAR2 value is compared to a CHAR value, non-blank-padding semantics are used. But, remember, when you assign a character value to a CHAR variable, if the value is shorter than the declared length of the variable, PL/SQL blank-pads the value to the declared length. Given the declarations
v_aa1 VARCHAR2(10) := 'ABC';
v_aa2 CHAR(10) := 'ABC'; -- PL/SQL blank-pads value
the following IF condition is false because the value of v_aa2 includes five trailing blanks:
IF v_aa1 = v_aa2 THEN ...
All string literals have datatype CHAR. If both values in a comparison are literals, blank-padding semantics are used. If one value is a literal, blank-padding semantics are used only if the other value has datatype CHAR.
Upvotes: 0
Reputation: 40563
Declare the table with a varchar2
:
create table abc (
aa varchar2(10)
);
Alternatively, declare v_aa
as char(10)
. But I would strongly assume that you should go the varchar2
route.
Update
So, I understand your chars stem back from a migration and you're ok to switch them to varchar2. You might want to run
select
'alter table ' || table_name ||
' modify ' || column_name ||
' varchar2(' || char_length ||');' stmt
from
user_tab_columns
where
data_type = 'CHAR';
This will produce alter table
statements (like so:)
alter table ABC modify AA varchar2(10);
which you can then run to change the definitions.
Of course, it (almost) goes without saying that you want to thoroughly test that before you apply it on your production database.
Upvotes: 0
Reputation: 231791
The issue comes down to whether you use char
or varchar2
comparison semantics in your queries. If you have a hard-coded string literal or a char(10)
variable, Oracle uses the char
comparison semantics which are to ignore the trailing white space. If you have a varchar2(10)
variable, Oracle uses the varchar2
comparison semantics which includes the trailing white space. Thus
select aa
into v_temp
from abc
where aa in (v_aa);
will return a row if v_aa
is defined as a char(10)
(or if it is replace with a string literal) but not if it is defined as a varchar(10)
.
This is one of the (many) reasons that most people avoid char
data types entirely. Personally, I don't mind the occasional char
for truly fixed-width data (i.e. char(1)
for flags and char(2)
for state codes) even though there is no benefit to using char
over varchar2
in those scenarios. For anything that is not fixed-width, however, using a char
makes no sense. You're just forcing Oracle to consume more space than it needs to and creating more work for yourself dealing with two sets of string comparison semantics (among other issues).
Upvotes: 2
Reputation: 7890
even if you use select aa from abc where aa in (cast('ABC' as varchar2(10)));
you will get no data because:
with varcha2(10) the length of the value of the field is 3 but with char(10) it is is 10
you need to define the v_aa
as char(10)
:
Declare
v_temp varchar2(10);
v_aa char(10) := 'ABC';
Begin
select aa into v_temp from abc where aa in (v_aa);
dbms_output.put_line(v_temp);
end;
OUTPUT: ABC
Upvotes: 0