1

我正在使用 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;

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

4

2 回答 2

1

您的字符串中没有多余的空格,如果是的话,您trim()将再次删除它们。SQL*Plus 只是以您不期望的方式格式化结果。文档提到了列类型的默认格式,通常可以为系统函数解决这个问题(尽管字符集可以使它比你预期的要大)。

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

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

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

所以它很安全,并允许它达到 a 的最大长度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

如您所见,它知道固定长度rpad和 a的长度substr(注意,由于多字节字符集,大小是实际字符串长度的四倍),但在rpad使用函数时会回落到最大值。

您看到的是 SQL*Plus 显示一个 4000 字符的列。如果您在 SQL Developer 中执行此操作,您会看到该列的标题确实是 4000 个字符。SQL*Plus 通过将显示的列标题减少到行大小来提供一点帮助,并将下一列换行到单独的行上。

于 2012-12-11T19:49:32.857 回答
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;
于 2012-11-30T09:01:58.010 回答