相同的字符串但不同的字节长度

Same string but different byte length

我在尝试 select 一些数据时遇到了一些问题。

我有一个插入其他 table 的触发器,但前提是另一个 table 中不存在字符串值,所以我在插入之前通过计数进行验证:

SELECT COUNT(*) INTO v_puesto_x_empresa FROM p_table_1 
            WHERE PUE_EMP_ID = Z.PIN_CODEMP
            AND PUE_NOMBRE = v_puesto_nombre;

如果上面的计数器小于 1 或等于 0,则进程允许将数据插入对应的 table。

事实证明,出于某种奇怪的原因正在复制数据,所以我检查了来源。 我使用游标来准备我需要插入的数据,我注意到对于某些字符串,即使它们相同,它也会将它们视为不同的字符串。

select 
    UPPER(trim(utl_raw.cast_to_varchar2(nlssort(PIN_DESCRIPCION, 'nls_sort=binary_ci')))) PIN_DESCRIPCION,
    LENGTHB(UPPER(trim(utl_raw.cast_to_varchar2(nlssort(PIN_DESCRIPCION, 'nls_sort=binary_ci'))))) LEGTHB,
    LENGTH(UPPER(trim(utl_raw.cast_to_varchar2(nlssort(PIN_DESCRIPCION, 'nls_sort=binary_ci'))))) AS "NORMAL LENGTH",
    LENGTHC(UPPER(trim(utl_raw.cast_to_varchar2(nlssort(PIN_DESCRIPCION, 'nls_sort=binary_ci'))))) AS "LENGTH C",
    LENGTH2(UPPER(trim(utl_raw.cast_to_varchar2(nlssort(PIN_DESCRIPCION, 'nls_sort=binary_ci'))))) AS "LENGTH 2"
    FROM PES_PUESTOS_INTERNOS
     where pin_codemp = '8F90CF5D287E2419E0530200000AA716'
     group by PIN_DESCRIPCION
     order by PIN_DESCRIPCION asc
     ;

结果如下:

结果,但在文本中:

PIN_DESCRIPCION
----------------------------------------------------------------------
    LEGTHB NORMAL LENGTH   LENGTH C   LENGTH 2
---------- ------------- ---------- ----------
ADMINISTRADOR DE PROCESOS                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                      
        27            27         27         27

ADMINISTRADOR DE PROCESOS Y CALIDAD                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                             
        36            36         36         36

AFORADOR                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                        
         9             9          9          9

AFORADOR                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                       
        10            10         10         10

ASISTENTE ADMINISTRATIVO                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                        
        25            25         25         25

ASISTENTE ADMINISTRATIVO                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                       
        26            26         26         26

所以我的猜测是,出于某种原因,即使它们是相同的,但在内部却以某种方式被视为不同。

注意:此 table 加载用户输入数据,因此结果虽然是 'same word',但可能会遇到一些语言字符差异,例如:

出于这个原因,我应用了下一段代码,所以我只能处理一个单词(字符串):

UPPER(trim(utl_raw.cast_to_varchar2(nlssort(PIN_DESCRIPCION, 'nls_sort=binary_ci'))))

因此,例如,如果我不使用它查询相同的数据,我将得到以下结果:

    PIN_DESCRIPCION                                                                                                                                                                                                                                                                                             
------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
administrador de procesos
administrador de procesos
Administrador de Procesos y Calidad
Aforador
aforador
aforador

对于此问题的任何帮助,我将不胜感激。

提前致谢。 谨致问候。

这个字符串不一样。第二个有另一个没有(显然)显示的字符。

如果你这样做:

SELECT PIN_DESCRIPCION,
       DUMP(PIN_DESCRIPCION)
FROM   PES_PUESTOS_INTERNOS
WHERE pin_codemp = '8F90CF5D287E2419E0530200000AA716'
GROUP BY PIN_DESCRIPCION
ORDER BY PIN_DESCRIPCION asc;

然后您将看到包含数据的二进制值,并且应该会看到有一个额外的尾随字符。这可能是:

  • 空格(您可以使用 RTRIM 删除);
  • 一个零宽度字符;
  • 一个NUL (ASCII 0) 字符;
  • 或未显示的其他内容。

例如,如果您有一个从字节(作为十六进制值传递)创建字符串的函数:

CREATE FUNCTION createString( hex VARCHAR2 ) RETURN VARCHAR2 DETERMINISTIC
IS
  value VARCHAR2(50);
BEGIN
  DBMS_STATS.CONVERT_RAW_VALUE( HEXTORAW( hex ), value );
  RETURN value;
END;
/

然后我们可以创建示例数据:

CREATE TABLE table_name ( value VARCHAR2(50) )
/

INSERT INTO table_name ( value )
SELECT 'AFORADOR' FROM DUAL UNION ALL
SELECT 'AFORADOR' || createString( '00' ) FROM DUAL UNION ALL
SELECT 'AFORADOR' || createString( '01' ) FROM DUAL
/

那么,如果我们使用:

SELECT value,
       DUMP( value ) AS dump,
       LENGTH(TRIM(value)) AS length
FROM   table_name

这输出:

|     VALUE |                                   DUMP | LENGTH |
|-----------|----------------------------------------|--------|
|  AFORADOR |   Typ=1 Len=8: 65,70,79,82,65,68,79,82 |      8 |
| AFORADOR | Typ=1 Len=9: 65,70,79,82,65,68,79,82,0 |      9 |
| AFORADOR | Typ=1 Len=9: 65,70,79,82,65,68,79,82,1 |      9 |

(是的,table 的对齐被搞乱了......那是因为字符串中的 unprintable 字符。)

sqlfiddle here


更新:

来自评论:

What is the output of SELECT DUMP(pin_descripcion) FROM <rest of your query> for those rows?

这些是结果:

Aforador   Typ=1 Len=8: 65,102,111,114,97,100,111,114
aforador  Typ=1 Len=9: 97,102,111,114,97,100,111,114,0

查看字节值的差异。

  • 第一个字符是65(或A)和97(或a);但是,通过使用 UPPER,您可以掩盖输出中的差异。如果您在 GROUP BY 中使用 UPPER 那么大小写的差异将无关紧要。
  • 此外,第二个在末尾有一个额外的字节,值为 0 (ASCII NUL),因此,无论大小写如何,它们都是不同的字符串。这个额外的最后一个字符不是 printable 所以你不会看到输出中的差异(并且用作字符串终止符所以可能会产生意想不到的副作用;例如,试图显示 NUL db<>fiddle 中的字符挂起输出)但这意味着字符串不同,因此 GROUP BY 不会将它们聚合在一起。

你可以这样做:

CREATE FUNCTION createStringFromHex( hex VARCHAR2 ) RETURN VARCHAR2 DETERMINISTIC
IS
  value VARCHAR2(50);
BEGIN
  DBMS_STATS.CONVERT_RAW_VALUE( HEXTORAW( hex ), value );
  RETURN value;
END;
/

然后,删除 NUL 字符串终止符:

UPDATE PES_PUESTOS_INTERNOS
SET    PIN_DESCRIPCION = RTRIM( PIN_DESCRIPCION, createStringFromHex( '00' ) )
WHERE  SUBSTR( PIN_DESCRIPCION, -1 ) = createStringFromHex( '00' );

那么你应该可以做到:

SELECT UPPER(PIN_DESCRIPCION) AS PIN_DESCRIPCION,
       LENGTH(UPPER(PIN_DESCRIPCION)) AS LENGTH
FROM   PES_PUESTOS_INTERNOS
--where pin_codemp = '8F90CF5D287E2419E0530200000AA716'
group by UPPER(PIN_DESCRIPCION)
order by UPPER(PIN_DESCRIPCION) asc;

并且只能看到单行。

db<>fiddle here