相同的字符串但不同的字节长度
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',但可能会遇到一些语言字符差异,例如:
- 用户输入 1:aforador
- 用户输入 2:Aforador
出于这个原因,我应用了下一段代码,所以我只能处理一个单词(字符串):
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
我在尝试 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',但可能会遇到一些语言字符差异,例如:
- 用户输入 1:aforador
- 用户输入 2:Aforador
出于这个原因,我应用了下一段代码,所以我只能处理一个单词(字符串):
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