RPAD中出现意外结果

时间:2012-11-30 05:39:00

标签: sql oracle

我正在使用Oracle 11g。我正在使用Scott帐户和演示EMP表。我用ENAME BRUCE WILLIAM插入了一条记录。我的目标是在两列中显示名字和姓氏。我用了这段代码:

select trim rpad(ename, instr(ename,' ')))   "First Name", 
       trim(substr(ename, instr(ename,' '))) "Last Name" 
  from emp;

这给出了一个奇怪的结果。 First Name扩展到第二行。我用了

select trim(substr(ename, 1, instr(ename,' '))), 
       trim(substr(ename, instr(ename, ' '))) 
  from emp;

我得到了预期的输出。我的问题是为什么第一行查询提供额外的空格?

2 个答案:

答案 0 :(得分:1)

你的字符串中没有多余的空格,如果你那么trim()会再次删除它们。 SQL * Plus只是以您不期望的方式格式化结果。 documentation提到了列类型的默认格式,并且通常可以将其用于系统函数(尽管characterset可以使它比预期的更大)。

似乎就像SQL * Plus一样,而SQL Developer无法确定rpad案例的合理默认值,但可以针对您的substr。好吧,SQL * Plus实际上只是从数据库中获取结果集游标,并使用游标元数据来确定要应用于显示字段的默认宽度,因此它没有获得您期望从该元数据获得的长度。但它应该使用多长时间?

如果填充长度是一个简单的值,数据库只知道rpad值有多大 - 它甚至不介意为零(它返回null,你依赖它)。如果填充长度由函数确定,则除了在返回元数据和实际数据之前计算结果集中的每个值之外,无法分辨结果有多大。这是不切实际的,并且随着数据的变化会产生不一致的输出。

尝试确定理论最大值也是不切实际的,即使它在您的情况下看起来很简单。 substr不能返回比原始值更长的内容;但是rpad即使从短输入值也可能产生巨大的东西,所以如果不能轻易确定限制(即从固定值),它必须允许这种可能性。

因此它可以安全地运行并且允许它达到varchar2的最大长度,这是4000个字符,正如这个动态SQL所示:

declare
    l_curid integer;
    l_desctab dbms_sql.desc_tab3;
    l_colcnt integer;
begin
    l_curid := dbms_sql.open_cursor;

    dbms_sql.parse(l_curid, 'select rpad(ename, instr(ename,'' '')), '
        || 'rpad(ename, 4), '
        || 'substr(ename, 1, instr(ename,'' '')) '
        || 'from emp where ename like ''B%''' , dbms_sql.native);

    dbms_sql.describe_columns3(l_curid, l_colcnt, l_desctab);

    for i in 1 .. l_colcnt loop
        dbms_output.put_line('column ' || i
            || ' ' || l_desctab(i).col_name
            || ' type ' || l_desctab(i).col_type
            || ' length ' || l_desctab(i).col_max_len
        );
    end loop;

    dbms_sql.close_cursor(l_curid);
end;
/

column 1 RPAD(ENAME,INSTR(ENAME,'')) type 1 length 4000
column 2 RPAD(ENAME,4) type 1 length 16
column 3 SUBSTR(ENAME,1,INSTR(ENAME,'')) type 1 length 40

正如您所看到的,它知道固定长度rpadsubstr的长度(请注意,由于多字节字符集,大小是实际字符串长度的四倍),但是后退使用函数到rpad的最大值。

您所看到的是SQL * Plus显示的4000-char列。如果你在SQL Developer中这样做,你会看到该列的标题确实是4000个字符。 SQL * Plus通过将显示的列标题减少到line size来帮助一点,并将下一列包装到一个单独的行上。

答案 1 :(得分:0)

lpad ('string', n [, 'string_pad')
rpad ('string', n [, 'string_pad')
使用string_pad将

字符串填充到长度为n。如果省略string_pad,将使用空格作为默认值 rpad是相似的,但垫右而不是左。

来自http://www.adp-gmbh.ch/ora/sql/rpad.html

这是理解

的好例子
begin

  for i in 1 .. 15 loop
    dbms_output.put_line(
      rpad('string', i) || '<'
    );
  end loop;

end;