Oracle varchar2 и тексты Unicode

Согласно спецификацииVARCHAR2(max_size CHAR) должен хранить max_size символов. Я наблюдаю другое/странное поведение для текстов Unicode.

Рассмотрим этот пример:

create table test (id varchar2(3 char) not null, primary key (id));

insert into test(id) values('abc');
insert into test(id) values('ффф');

Query 1 ERROR: ORA-12899: value too large for column "TEST"."TEST"."ID" (actual: 6, maximum: 3)

Итак, 3 символа varchar2 на самом деле означают то же самое, что и байт? НЕТ :)

create table test (id varchar2(3 byte) not null, primary key (id))

insert into test(id) values('abc')
insert into test(id) values('ффф')

Query 1 ERROR: ORA-12899: value too large for column "TEST"."TEST"."ID" (actual: 18, maximum: 3)

И мой вопрос остается, как сообщить Oracle, что длина varchar2 предназначена для текста Unicode (точнее, UTF8)?

Обновление: можно ли записать SQL-запрос, который покажет все таблицы/столбцы, длина которых была в байтах?

На самом деле, моя проблема разделена на 2 части: неправильная кодировка запроса TablePlus, длина в байтах (без суффикса char) для случайных столбцов :)

Обновление 2: спасибо @Wernfried Domscheit!

Запрос показывает таблицу и столбцы с varchar2, длина которых указана в bytes:

SELECT TABLE_NAME, COLUMN_NAME, DATA_LENGTH, CHAR_USED
FROM USER_TAB_COLUMNS WHERE DATA_TYPE = 'VARCHAR2' AND CHAR_USED = 'B'
ReactJs | Supabase | Добавление данных в базу данных
ReactJs | Supabase | Добавление данных в базу данных
Это и есть ваш редактор таблиц в supabase.👇
Понимание Python и переход к SQL
Понимание Python и переход к SQL
Перед нами лабораторная работа по BloodOath:
0
0
1 757
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий

Ваш пример работает для меня:

SELECT * 
FROM V$NLS_PARAMETERS 
WHERE PARAMETER = 'NLS_CHARACTERSET';

PARAMETER          VALUE      
------------------------------
NLS_CHARACTERSET   AL32UTF8   

1 row selected.



CREATE TABLE TEST (ID VARCHAR2(3 CHAR));
Table created.

INSERT INTO TEST(ID) VALUES('abc');
1 row created.

INSERT INTO TEST(ID) VALUES('ффф');
1 row created.

Может у вас опечатка?

Обновлять:

Похоже, ваш клиент использует неправильные настройки символов.

ф (U+0444: кириллическая строчная буква Ef) имеет следующие значения байтов:

+-------------------------------------------------------------------------------+
|Encoding|hex        |dec (bytes)|dec       |binary                             |
+-------------------------------------------------------------------------------+
|UTF-8   |D1 84      |209 132    |53636     |11010001 10000100                  |
|UTF-16BE|04 44      |4 68       |1092      |00000100 01000100                  |
|UTF-16LE|44 04      |68 4       |17412     |01000100 00000100                  |
|UTF-32BE|00 00 04 44|0 0 4 68   |1092      |00000000 00000000 00000100 01000100|
|UTF-32LE|44 04 00 00|68 4 0 0   |1141112832|01000100 00000100 00000000 00000000|
+-------------------------------------------------------------------------------+

DUMP должен вернуться Typ=1 Len=6 CharacterSet=AL32UTF8: d1,84,d1,84,d1,84, но вы получите ef,bf,bd, который является U+FFFD: Символ замены

Вы не вставляете ффф, он преобразуется в ���.

Я предполагаю, что на самом деле ваш клиент использует UTF-8, но вы не сообщили базе данных, поэтому, скорее всего, база данных предполагает, что клиент использует значение по умолчанию US7ASCII (или что-то еще). Клиент отправляет 6 байтов (d1,84,d1,84,d1,84), но база данных Oracle интерпретирует их как 6 однобайтовых символов.

Обычно вы используете переменную среды NLS_LANG, чтобы определить это. Однако dbeaver основан на Java, а Java/JDBC не использует настройки NLS_LANG — по крайней мере, по умолчанию.

Неа. SELECT * FROM V$NLS_PARAMETERS WHERE PARAMETER = 'NLS_CHARACTERSET' NLS_CHARACTERSET AL32UTF8 Может ли такое поведение быть привязано к версии/выпуску Oracle?

FoxyBOA 10.12.2020 12:57

Перепроверил с помощью вашего SQL (скопируйте и вставьте в консоль + удалите существующую тестовую таблицу). Та же ошибка. Моя версия базы данных: "Oracle Database 11g Express Edition Release 11.2.0.2.0 - 64-битная версия"

FoxyBOA 10.12.2020 13:04

Какой инструмент вы используете? Попробуйте INSERT INTO TEST(ID) VALUES('ф') и проверьте с помощью DUMP(), что на самом деле было вставлено.

Wernfried Domscheit 10.12.2020 13:46

TablePlus, dbeaver или Oracle jdbc (тонкий) драйвер Java

FoxyBOA 10.12.2020 14:13

Что вы получаете от SELECT DUMP(ID, 1016) FROM TEST;?

Wernfried Domscheit 10.12.2020 14:30

Тип=1 Len=6 CharacterSet=AL32UTF8: ef,bf,bd,ef,bf,bd

FoxyBOA 10.12.2020 15:10

Ты прав! Это ДВЕ разные проблемы: TablePlus неправильно установил кодировку запроса. Некоторые столбцы были предоставлены без обозначения char (т.е. были в байтах!) Можно ли написать скрипт, который показывает все таблицы/столбцы, где длина varchar указана в байтах?

FoxyBOA 11.12.2020 12:47

Да, попробуйте SELECT TABLE_NAME, COLUMN_NAME, DATA_LENGTH, CHAR_USED FROM USER_TAB_COLUMNS WHERE DATA_TYPE = 'VARCHAR2' AND CHAR_USED = 'B' Также, если вы не укажете ни BYTE, ни CHAR, то по умолчанию задается параметр сеанса NLS_LENGTH_SEMANTICS

Wernfried Domscheit 11.12.2020 13:40

Другие вопросы по теме