LENGTH命令的奇怪行为 - ORACLE

时间:2013-11-04 18:00:11

标签: sql oracle

我在这里遇到了一个我无法理解的错误情况。我写的关于函数的文档也没有什么可以点亮这个东西。

我有一个包含字段titulo varchar2(55)的表格。我在巴西,这个领域的一些角色有重音符号,我的目标是创建一个没有重音的类似字段(由原始字符替换为á变为a等等。 )。

我可以使用一堆函数来执行replacetranslate和其他功能,但我在互联网上找到一个接口更优雅,然后我使用它。这就是问题所在。

我的更新代码如下:

update myTable 
   set TITULO_URL = replace(
                 utl_raw.cast_to_varchar2(
                           nlssort(titulo, 'nls_sort=binary_ai')
                                         )
                            ,' ','_');

正如我所说,目标是转换其等效的每个重音字符,而没有重音加上_的空格字符

然后我收到了这个错误:

ORA-12899: value too large for column 
     "mySchem"."myTable"."TITULO_URL" (actual: 56, maximum: 55)

起初,我可能会添加一些角色,让我检查一下。我做了一个select命令,让我得到titulo有55个字符的行。

select titulo from myTable where length(titulo) = 55

然后我选择一行来做一些测试,我选择的行有这个值:'FGHJTÓRYO DE YHJKS DA DGHQÇÃA DE ASGA XCVBGL EASDEÔNASD'(我确实改了一下来保存数据,但结果是一样的)

当我执行以下select语句时,事情变得奇怪了:

select a, length(a), b, length(b)
  from ( select 'FGHJTÓRYO DE YHJKS DA DGHQÇÃA DE ASGA XCVBGL EASDEÔNASD' a,
                replace(
                   utl_raw.cast_to_varchar2( 
                               nlssort('FGHJTÓRYO DE YHJKS DA DGHQÇÃA DE ASGA XCVBGL EASDEÔNASD', 'nls_sort=binary_ai')
                                           )
                       ,' ','_') b
           from dual
       )

这个sql的结果是(为了更好的可视化,我将把值降低一个):

                     a                                       LENGTH(a)
FGHJTÓRYO DE YHJKS DA DGHQÇÃA DE ASGA XCVBGL EASDEÔNASD        55     
                     b                                       LENGTH(b)
fghjtoryo_de_yhjks_da_dghqcaa_de_asga_xcvbgl_easdeonasd        56

比较两个字符串一个在另一个上面,没有大小差异:

FGHJTÓRYO DE YHJKS DA DGHQÇÃA DE ASGA XCVBGL EASDEÔNASD
fghjtoryo_de_yhjks_da_dghqcaa_de_asga_xcvbgl_easdeonasd

我已经在Toad,PLSQL Developer和SQLPLUSW上测试了这个查询,结果相同。所以我的问题是这个LENGTH(b)= 56来自?我知道它可以是字符集,但我无法弄清楚为什么。我甚至用trim命令进行了测试,结果是一样的。

我做过的另一项测试

  • substr(b, 1,55)结果与上面的内容相同
  • lenght(trim(b))结果是56
  • substr(b,56)结果为空(没有空,没有空格,只是空)

@Sebas建议:

  • LENGTHB(b)结果是56
  • ASCII(substr(b,56))

那么,再次:这个LENGTH(b)= 56来自

很抱歉这篇长篇文章感谢那些到这里来的人(阅读所有内容)。 感谢那些不读书的人:)

祝你好运

3 个答案:

答案 0 :(得分:3)

'nlssort'函数的文档没有声明输出字符串是输入字符串的规范化,或者它们将具有相同的长度。该函数的目的是返回可用于对输入字符串进行排序的数据。

请参阅http://docs.oracle.com/cd/E11882_01/server.112/e26088/functions113.htm#SQLRF51561

很有可能用它来标准化你的字符串,因为显然它有效,但你在这里赌博......

哎呀,它甚至可以产生 LENGTH(b)= 200 仍然正在做它应该做的事情:)

答案 1 :(得分:1)

1)Oracle区分字节长度和字符长度:varchar2(55)表示55个字节,因此只有幸运时才有55个UTF-8字符:您应该将字段声明为varchar2 (55 char)。< / p>

2)像

这样的扭曲
replace(utl_raw.cast_to_varchar2(nlssort(
'FGHJTÓRYO DE YHJKS DA DGHQÇÃA DE ASGA XCVBGL EASDEÔNASD', 
'nls_sort=binary_ai')),' ','_') b

是胡说八道,你只是用类似的字符串替换字符串。 您的数据库有一个编码,所有字符串都用该编码表示,它确定它们的长度(以字节为单位); mcalmeida解释的任意变化引入了随机数据相关的噪声,如果你进行比较,这绝不是一件好事。

3)关于删除重音的规定任务,你应该自己使用REPLACE,TRANSLATE等,因为只有你知道你的要求;它不是Unicode规范化或任何“标准”,没有捷径。 您可以定义一个函数并从任何查询和任何PL / SQL程序中调用它,而不会进行丑陋的复制和粘贴。

答案 2 :(得分:0)

函数“nlssort()”在字符串的原始二进制文件末尾返回带有额外00的二进制文件。

测试:

select NLSSORT('abc') from dual

输出:

  

61626300

可以通过从NLSSORT的返回中删除最后2位来解决此问题。

解决方案:

  select a, length(a), b, length(b)   
    from ( select 'FGHJTÓRYO DE YHJKS DA DGHQÇÃA DE ASGA XCVBGL EASDEÔNASD' a,
                  replace(
                      utl_raw.cast_to_varchar2( 
                                 substr(nlssort('FGHJTÓRYO DE YHJKS DA DGHQÇÃA DE ASGA XCVBGL EASDEÔNASD', 'nls_sort=binary_ai'),1, 
                                                  length(nlssort('FGHJTÓRYO DE YHJKS DA DGHQÇÃA DE ASGA XCVBGL EASDEÔNASD', 'nls_sort=binary_ai'))-2 
                                                 )
                                          )

                         ,' ','_') b
             from dual
     )

  )