简体   繁体   English

在Oracle中具有char数据类型的查询列

[英]Query column with char data type in oracle

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');" -上面的pl / sql块一次执行不输出任何内容,但是如果我用“从abc中选择aa到v_temp中,从a到('ABC')中的aa替换”来替换该块中的select, the value will be printed. 该值将被打印。

Please advice me on the behaviour. 请就行为向我提出建议。

The issue comes down to whether you use char or varchar2 comparison semantics in your queries. 问题归结于在查询中使用char还是varchar2比较语义。 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. 如果您具有硬编码的字符串文字或char(10)变量,则Oracle使用的char比较语义将忽略尾随空白。 If you have a varchar2(10) variable, Oracle uses the varchar2 comparison semantics which includes the trailing white space. 如果您具有varchar2(10)变量,则Oracle使用varchar2比较语义,其中包括结尾空格。 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) . 如果将v_aa定义为char(10) (或者如果将其替换为字符串文字),则将返回一行,但如果将其定义为varchar(10)则不会返回行。

This is one of the (many) reasons that most people avoid char data types entirely. 这是大多数人完全避免使用char数据类型的(许多)原​​因之一。 Personally, I don't mind the occasional char for truly fixed-width data (ie char(1) for flags and char(2) for state codes) even though there is no benefit to using char over varchar2 in those scenarios. 就个人而言,我不介意偶尔的char为真正的固定宽度的数据(即char(1)用于标记和char(2)对于状态代码),即使有使用没有好处char超过varchar2在这些场景。 For anything that is not fixed-width, however, using a char makes no sense. 对于任何非固定宽度的内容,使用char都没有意义。 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). 您只是在强迫Oracle消耗比其需要更多的空间,并为自己处理两组字符串比较语义(还有其他问题)创建更多的工作。

Declare the table with a varchar2 : varchar2声明表:

create table abc (
   aa varchar2(10)
);

Alternatively, declare v_aa as char(10) . 或者,将v_aa声明为char(10) But I would strongly assume that you should go the varchar2 route. 但是我强烈建议您应该使用varchar2路由。

Update 更新

So, I understand your chars stem back from a migration and you're ok to switch them to varchar2. 因此,我了解您的字符源于迁移,并且可以将其切换为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语句(如下所示:)

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. 当然,(几乎)不用说,您想在将其应用于生产数据库之前进行彻底的测试。

even if you use select aa from abc where aa in (cast('ABC' as varchar2(10))); 即使您使用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) : 您需要将v_aa定义为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 输出: ABC

If a VARCHAR2 value is compared to a CHAR value, non-blank-padding semantics are used. 如果将VARCHAR2值与CHAR值进行比较,则使用非空白填充语义。 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. 但是,请记住,将字符值分配给CHAR变量时,如果该值短于变量的声明长度,则PL / SQL空白将值填充到声明的长度。 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: 由于v_aa2的值包含五个尾随空白,因此以下IF条件为false:

IF v_aa1 = v_aa2 THEN ...

All string literals have datatype CHAR. 所有字符串文字的数据类型均为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. 如果一个值是文字,则仅当另一个值的数据类型为CHAR时才使用空白填充语义。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM