Использование русского языка и символов кириллицы в базах данных oracle | материализация идей
1 select * from nls_database_parameters
2* where parameter like ‘%CHARACTERSET’
15:14:49 SQL> /
PARAMETER VALUE
—————————— ————————-
NLS_CHARACTERSET AL32UTF8
NLS_NCHAR_CHARACTERSET AL16UTF16
Обратим внимание на значение параметра “NLS_CHARACTERSET” равное “AL32UTF8” (и проигнорируем “NLS_NCHAR_CHARACTERSET” – изучение этого параметра выходит за рамки нашей заметки. Также существует инициализационный параметр “NLS_LENGTH_SEMANTICS”, который нужно устанавливать только на уровне сессии пользователя, но не для всего экземпляра оракла, обязательно прочтите про “NLS_LENGTH_SEMANTICS” в документации). Кодировка AL32UTF8 – это “ораклячая” версия UTF8 кодировки для набора символов Unicode. AL32UTF8 использует один байт для ASCII символов и до четырёх байт для всех остальных. Не используйте “ораклячую” UTF8 никогда – несмотря на совпадение имени, эта кодировка может занимать до шести байт для одного символа. Ещё раз – название кодировки “utf8” в Oracle – AL32UTF8.Проверим, какую кодировку будут использовать наш клиент (sqlplus) и оболочка Линукс (bash).
[ora11@attack ~]$ env | grep LANGNLS_LANG=English_America.AL32UTF8
LANG=en_US.utf8
[ora11@attack ~]$
[ora11@attack ~]$ locale -a | grep ru
ru_RU
ru_RU.iso88595
ru_RU.koi8r
ru_RU.utf8
russian
ru_UA
ru_UA.koi8u
ru_UA.utf8
[ora11@attack ~]$
Заметьте, что переменная NLS_LANG используется Ораклом и поэтому “играет по его правилам” – название кодировки Unicode в этой переменной обычно должно совпадать со значением NLS_CHARACTERSET в базе данных. Оболочка линукса bash использует значения, продиктованные стандартной библиотекой C (их можно вывести командой “locale -a”). В нашем примере мы не используем значение “ru_RU.utf8” чтобы не пугаться русских фраз в линуксе. Посмотрите ниже как это выглядит.
[ora11@attack ~]$ echo $LANGen_US.utf8
[ora11@attack ~]$ ls $
ls: cannot access $: No such file or directory
[ora11@attack ~]$
[ora11@attack ~]$ export LANG=ru_RU.utf8
[ora11@attack ~]$ echo $LANG
ru_RU.utf8
[ora11@attack ~]$ ls $
ls: невозможно получить доступ к $: Нет такого файла или каталога
[ora11@attack ~]$
Таким образом, первая часть значения переменной LANG определяет на каком языке (и для какой страны) с вами будет разговаривать Линукс, а вторая часть после точки задаёт кодировку набора символов.Как мы убедились, и Оракл и Линукс будут разговаривать с нами используя одну и ту же кодировку UTF8 и набор символов Unicode. Таков же и формат текстовых записей внутри базы данных (NLS_CHARACTERSET). Установку кодовой страницы терминала Гном проверим зайдя в меню “Terminal”-“Set Character Encoding”. Должно быть отмечено значение “Unicode (UTF-8)”Проверим работу всей цепочки.
— Можно использовать “character semantics”:
— create table t (id number, msg varchar2(100 CHAR));
— В наших примерах мы используем “byte semantics”.
15:45:10 SQL> create table t (id number, msg varchar2(100));
Table created.
Elapsed: 00:00:00.37
15:45:42 SQL> insert into t values (1, ‘Тест 1’);
1 row created.
Elapsed: 00:00:00.01
15:46:02 SQL> insert into t values (2, ‘Проверка 2’);
1 row created.
Elapsed: 00:00:00.00
15:46:23 SQL> commit;
Commit complete.
Elapsed: 00:00:00.02
15:46:25 SQL> col msg for a25
15:46:39 SQL> select * from t;
ID MSG
———- ————————-
1 Тест 1
2 Проверка 2
2 rows selected.
Elapsed: 00:00:00.01
15:46:44 SQL>
15:48:01 SQL> select * from t where msg like ‘Про%’;
ID MSG
———- ————————-
2 Проверка 2
1 row selected.
Elapsed: 00:00:00.01
15:48:17 SQL> select * from t where upper (msg) = ‘ТЕСТ 1’;
ID MSG
———- ————————-
1 Тест 1
1 row selected.
Elapsed: 00:00:00.01
15:48:53 SQL> select lower(msg) from t;
LOWER(MSG)
————————————
тест 1
проверка 2
2 rows selected.
Elapsed: 00:00:00.01
15:49:05 SQL>
Очевидно, что мы не только можем сохранить и вновь прочесть введённые записи, но и в состоянии правильно обработать их, используя встроенные функции Оракла. Что произойдёт, если мы изменим одно из значений в нашей “цепи”?
[ora11@attack ~]$ env | grep LANGNLS_LANG=English_America.AL32UTF8
LANG=ru_RU.koi8r
[ora11@attack ~]$ [ora11@attack ~]$ sqlplus -s / as sysdba
select * from t;
ID
———-
MSG
————————–
1
п╒п╣я│я┌ 1
2
п÷я─п╬п╡п╣я─п╨п╟ 2
2 rows selected.
[ora11@attack ~]$[ora11@attack ~]$ env | grep LANG
NLS_LANG=English_America.CL8ISO8859P5
LANG=en_US.utf8
[ora11@attack ~]$sqlplus -s / as sysdba
select * from t;
ID
———-
MSG
—————————
1
���� 1
2
�������� 2
2 rows selected.
Если вы установите значение NLS_LANG в что-то несуществующее в представлении “v$NLS_VALID_VALUES”, на экране возникнет ошибка “ORA-12705: Cannot access NLS data files or invalid environment specified”. Но даже если одна из переменных окружения LANG или NLS_LANG будет установлена в правильное, но не совпадающее с базой данных (NLS_CHARACTERSET) значение – данные будет невозможно прочесть.Single byte – Данные сохраняются в КОИ-8Как сказано выше, сохранение русского текста в формате Юникод имеет нежелательный побочный эффект – объём данных удваивается. В большинстве случаев это не является проблемой и использование набора символов AL32UTF8 рекомендовано к использованию во всех базах данных Oracle.В то же время, я чётко вижу два сценария когда я бы предпочёл Юникоду какую-либо однобайтную кодировку, например КОИ-8. Во-первых, для очень большой базы с большим содержанием текстовой информации размером, скажем в 300Тб, разница в цене дисковой памяти между 600Тб и 300Тб слишком велика, чтобы пренебречь ею ради стандартизации. Во-вторых, при использовании Oracle XE, где максимальный размер хранимых данных ограничен производителем.В начале проверим, соответствует ли практика нашей теории.
— Вставляем русский текст в кодировке AL32UTF8, 2 байта на символ
declare i number;
begin
for i in 1..400 loop
insert into t values (i, ‘тестируем’);
end loop;
commit;
end;
/
16:29:48 SQL> /
PL/SQL procedure successfully completed.
Elapsed: 00:00:00.07
16:29:49 SQL> select count(*) from t;
COUNT(*)
———-
400
1 row selected.
Elapsed: 00:00:00.00
16:29:56 SQL>
16:31:43 SQL> exec dbms_stats.gather_table_stats(‘SYS’, ‘T’);
PL/SQL procedure successfully completed.
Elapsed: 00:00:00.97
16:31:53 SQL>
16:32:14 SQL> select NUM_ROWS, blocks, AVG_SPACE, AVG_ROW_LEN
16:32:55 2 from dba_tables
16:33:03 3 where table_name = ‘T’;
NUM_ROWS BLOCKS AVG_SPACE AVG_ROW_LEN
———- ———- ———- ———–
400 3 0 41
1 row selected.
Elapsed: 00:00:00.03
16:33:10 SQL>
16:33:10 SQL> truncate table t;
Table truncated.
Elapsed: 00:00:00.12
16:34:51 SQL>
— Теперь тот же текст, но в ASCII одно-байтных символах
declare i number;
begin
for i in 1..400 loop
insert into t values (i, ‘testiruem’);
end loop;
commit;
end;
/
PL/SQL procedure successfully completed.
Elapsed: 00:00:00.06
16:36:02 SQL> exec dbms_stats.gather_table_stats(‘SYS’, ‘T’);
PL/SQL procedure successfully completed.
Elapsed: 00:00:00.10
16:36:20 SQL> select NUM_ROWS, blocks, AVG_SPACE, AVG_ROW_LEN
16:36:27 2 from dba_tables
16:36:30 3 where table_name = ‘T’;
NUM_ROWS BLOCKS AVG_SPACE AVG_ROW_LEN
———- ———- ———- ———–
400 2 0 14
1 row selected.
Elapsed: 00:00:00.00
16:36:33 SQL>
Мы видим почти 3-х кратную разницу в размере одной записи. Дополнительное место занимают внутренние служебные структуры базы данных. Таким образом, наша терория подтверждена практикой. И, поскольку мы используем Oracle XE, посмотрим как можно использовать кодировку КОИ-8 чтобы снизить объём данных и в то же время не потерять функциональность работы с русскими символами.
………… == Послание к Ефесянам святого апостола Павла == …………….
=== Глава 3, Стих 17 ===
14 Для сего преклоняю колени мои пред Отцем Господа нашего Иисуса Христа,
15 от Которого именуется всякое отечество на небесах и на земле,
16 да даст вам, по богатству славы Своей, крепко утвердиться Духом Его во
внутреннем человеке,
17 верою вселиться Христу в сердца ваши,
18 чтобы вы, укорененные и утвержденные в любви, могли постигнуть со всеми
святыми, что широта и долгота, и глубина и высота,
19 и уразуметь превосходящую разумение любовь Христову, дабы вам
исполниться всею полнотою Божиею.
(b /b-, c /c-, /-, *) >
[oracle@attack ~]$
[oracle@attack ~]$ sqlplus
SQL*Plus: Release 11.2.0.2.0 Production on Wed Oct 12 16:56:09 2021
Copyright (c) 1982, 2021, Oracle. All rights reserved.
Enter user-name: / as sysdba
Connected to:
Oracle Database 11g Express Edition Release 11.2.0.2.0 – 64bit Production
16:56:18 SQL>
1 select * from nls_database_parameters
2* where parameter = ‘NLS_CHARACTERSET’
16:57:26 SQL> /
PARAMETER VALUE
————————- ————————-
NLS_CHARACTERSET CL8KOI8R
1 row selected.
Elapsed: 00:00:00.00
16:57:27 SQL>
16:57:27 SQL> !env | grep LANG
NLS_LANG=American_America.CL8KOI8R
LANG=en_US.koi8r
16:57:51 SQL>
16:57:51 SQL> create table t (id number, msg varchar2(100));
Table created.
Elapsed: 00:00:00.39
16:58:47 SQL> insert into t values (1, ‘Тестируем русский в КОИ-8’);
1 row created.
Elapsed: 00:00:00.01
16:59:16 SQL> commit;
Commit complete.
Elapsed: 00:00:00.02
16:59:18 SQL> select * from t;
ID
———-
MSG
—————————
1
Тестируем русский в КОИ-8
1 row selected.
Elapsed: 00:00:00.01
16:59:22 SQL>
Те же самые правила работают – кодировки всех “звеньев” в нашей цепи программных средств должны совпадать. База данных и клиент Оракла работают в кодировке “CL8KOI8R”, локаль системы установлена в “koi8r” и эмулятор терминала использует кодовую страницу “Cyrillic (KOI8-R)”. Удостоверимся, что использование одно-байтной кодировки позволяет нам существенно уменьшить размер записи.
declare i number;
begin
for i in 1..400 loop
insert into t values (i, ‘тестируем’);
end loop;
commit;
end;
/
PL/SQL procedure successfully completed.
Elapsed: 00:00:00.06
17:10:54 SQL> exec dbms_stats.gather_table_stats(‘SYS’, ‘T’);
PL/SQL procedure successfully completed.
Elapsed: 00:00:00.07
17:11:01 SQL> select NUM_ROWS, blocks, AVG_SPACE, AVG_ROW_LEN
17:11:06 2 from dba_tables
17:11:11 3 where table_name = ‘T’;
NUM_ROWS BLOCKS AVG_SPACE AVG_ROW_LEN
———- ———- ———- ———–
400 2 0 14
1 row selected.
Elapsed: 00:00:00.01
17:11:15 SQL> select * from t where rownum <5;
ID
———-
MSG
—————————————-
1
Тестируем
2
Тестируем
3
Тестируем
4
Тестируем
4 rows selected.
Elapsed: 00:00:00.01
17:11:27 SQL>
В заключение надо отметить, что Оракл может конвертировать данные из одного набора симболов в другой “налету”, такой эффект достигается установкой переменных окружения LANG и NLS_LANG в одно значение, соответствующее текущей локали операционной системы. В это же время NLS_CHARACTERSET “внутри” базы данных может отличаться от среды окружения пользователя – и в этом случае Оракл произведёт конвертирование данных, как показано ниже.
[ora11@NAU ~]$ sqlplusSQL*Plus: Release 11.2.0.2.0 Production on Чт Окт 13 12:03:37 2021
Copyright (c) 1982, 2021, Oracle. All rights reserved.
Введите имя пользователя: / as sysdba
Присоединен к:
Oracle Database 11g Release 11.2.0.2.0 – Production
12:03:40 SQL> select * from nls_database_parameters;
PARAMETER VALUE
—————————— —————————————-
NLS_LANGUAGE AMERICAN
NLS_TERRITORY AMERICA
NLS_CURRENCY $
NLS_ISO_CURRENCY AMERICA
NLS_NUMERIC_CHARACTERS .,
NLS_CHARACTERSET CL8ISO8859P5
NLS_CALENDAR GREGORIAN
NLS_DATE_FORMAT DD-MON-RR
NLS_DATE_LANGUAGE AMERICAN
NLS_SORT BINARY
NLS_TIME_FORMAT HH.MI.SSXFF AM
NLS_TIMESTAMP_FORMAT DD-MON-RR HH.MI.SSXFF AM
NLS_TIME_TZ_FORMAT HH.MI.SSXFF AM TZR
NLS_TIMESTAMP_TZ_FORMAT DD-MON-RR HH.MI.SSXFF AM TZR
NLS_DUAL_CURRENCY $
NLS_COMP BINARY
NLS_LENGTH_SEMANTICS BYTE
NLS_NCHAR_CONV_EXCP FALSE
NLS_NCHAR_CHARACTERSET AL16UTF16
NLS_RDBMS_VERSION 11.2.0.2.0
20 строк выбрано.
Затрач.время: 00:00:00.01
12:03:52 SQL> !env | grep LANG
NLS_LANG=Russian_Russia.CL8KOI8R
LANG=ru_RU.koi8r
12:04:00 SQL> select * from t where rownum <3;
ID
———-
MSG
——————————–
1
Тестируем
2
Тестируем
2 строк выбрано.
Затрач.время: 00:00:00.01
12:04:09 SQL> Отсоединено от Oracle Database 11g Release 11.2.0.2.0 – Production
[ora11@NAU ~]$
Как видно, работать с русскими символами в Оракле просто. Всё что необходимо – помнить о том, какую кодировку использует база данных и настраивать клиента, локаль и эмулятор терминала соответственно.Другие средства разработки также успешно будут работать с вашими данными – и в AL32UTF8, и в CL8KOI8R. В качестве упражнения я предлагаю читателю установить Oracle SQL Developer и проверить его работу с русским текстом в таблице “Т”. Не забудьте проверить какую кодировку (и как) устанавливает для вас эта java-программа.
Функции юникода
Поддержка Юникода в PL/SQL начинается с простейших строковых функций. Впрочем, в табл. 2 видны небольшие отличия этих функций от их хорошо известных аналогов.
К именам функций INSTR, LENGTH и SUBSTR добавляется суффикс B, C, 2 или 4; он означает, что функция работает с байтами, символами, кодовыми единицами или кодовыми точками соответственно.
Функции INSTR, LENGTH и SUBSTR используют семантику длины, связанную с типом данных столбца или переменной. Эти базовые функции и версии с суффиксом C часто возвращают одинаковые значения — до тех пор, пока вы не начнете работать со значениями NCHAR или NVARCHAR.
Поскольку NLS_NCHAR_ CHARACTERSET и NLS_CHARACTERSET могут различаться, результат вызова INSTR, LENGTH и SUBSTR может отличаться (в зависимости от типа данных) от результата их символьных аналогов.
Таблица 2. Функции Юникода
Функция Юникода | Описание |
ASCIISTR(string) | Преобразует строку string в ASCn -символы. Строки в Юникоде преобразуются в стандартный формат xxxx |
COMPOSE(string) | Преобразует строку string, полученную в результате декомпозиции, в полную композиционную форму |
DECOMPOSE(string, [canonical | compatibility]) | Получает строку string и возвращает строку Юникода, полученную разложением составных символов на кодовые |
INSTRB(string, substr, pos, occ) | Возвращает позицию подстроки substr в строке string в байтах, начиная с позиции pos. Аргумент occ задает номер вхождения substr, если подстрока встречается более одного раза. По умолчанию аргументы pos и occ |
INSTRC(string, substr, pos, occ) | Аналог INSTRB — за исключением того, что возвращает позицию substr в string в символах, начиная с позиции pos (значение pos задается в символах) |
INSTR2(string, substr, pos, occ) | Возвращаемая позиция задается в кодовых единицах UTF -16 |
INSTR4(string, substr, pos, occ) | Возвращаемая позиция задается в кодовых точках UTF -16 |
LENGTHB(string) | Возвращает размер строки string в байтах |
LENGTHC(string) | Возвращает длину строки string в символах Юникода |
LENGTH2(string) | Возвращаемая длина задается в кодовых единицах UTF -16 |
LENGTH4(string) | Возвращаемая длина задается в кодовых точках UTF -16 |
SUBSTRB(string, n, m) | Возвращает часть строки string, состоящую из m символов, начиная с позиции n. Значения n и m задаются в байтах |
SUBSTRC(string, n, m) | Возвращает часть строки string, состоящую из m символов, начиная с позиции n. Значения n и m задаются в символах Юникода |
SUBSTR2(string, n, m) | Значения n и m задаются в кодовых единицах UTF -16 |
SUBSTR4(string, n, m) | Значения n и m задаются в кодовых точках UTF -16 |
UNISTR | Преобразует представление строки string из ASCII -формата (обрат-ная косая черта, шестнадцатеричные цифры) в Юникод |
Рассмотрим эти функции подробнее.
ASCIISTR
ASCIISTR пытается преобразовать полученную строку в ASCII-символы. Если строка содержит символы, отсутствующие в наборе ASCII, они представляются в формате xxxx. Как будет показано ниже при описании функции DECOMPOSE, такое форматирование иногда оказывается очень удобным.
BEGIN
DBMS_OUTPUT.put_line ('ASCII Character: ' || ASCIISTR ('A'));
DBMS_OUTPUT.put_line ('Unicode Character: ' || ASCIISTR ('Ä'));
END;
Результат:
ASCII Character: A
Unicode Character: 0C4
COMPOSE
Некоторые символы могут иметь несколько вариантов представления кодовых пунктов. Это создает проблемы при сравнении двух значений. Символ А может быть представлен как одним кодовым пунктом U 00C4, так и двумя кодовыми пунктами U 0041 (буква A) и U 0308. При сравнении PL/SQL считает, что эти два варианта представления не равны.
DECLARE
v_precomposed VARCHAR2 (20) := UNISTR ('0C4');
v_decomposed VARCHAR2 (20) := UNISTR ('A308');
BEGIN
IF v_precomposed = v_decomposed
THEN
DBMS_OUTPUT.put_line ('==EQUAL==');
ELSE
DBMS_OUTPUT.put_line ('<>NOT EQUAL<>');
END IF;
END;
Результат:
Однако после использования функции COMPOSE эти две версии равны:
DECLARE
v_precomposed VARCHAR2 (20) := UNISTR ('0C4');
v_decomposed VARCHAR2 (20) := COMPOSE (UNISTR ('A308'));
BEGIN
IF v_precomposed = v_decomposed
THEN
DBMS_OUTPUT.put_line ('==EQUAL==');
ELSE
DBMS_OUTPUT.put_line ('<>NOT EQUAL<>');
END IF;
END;
На этот раз сравнение дает другой результат:
==EQUAL==
DECOMPOSE
Как нетрудно догадаться, функция DECOMPOSE является обратной по отношению к COMPOSE: она разбивает составные символы на отдельные кодовые точки или элементы:
DECLARE
v_precomposed VARCHAR2 (20) := ASCIISTR (DECOMPOSE ('Ä'));
v_decomposed VARCHAR2 (20) := 'A308';
BEGIN
IF v_precomposed = v_decomposed
THEN
DBMS_OUTPUT.put_line ('==EQUAL==');
ELSE
DBMS_OUTPUT.put_line ('<>NOT EQUAL<>');
END IF;
END;
Результат:
==EQUAL==
INSTR/INSTRB/INSTRC/INSTR2/INSTR4
Все функции INSTR возвращают позицию подстроки внутри строки и различаются лишь по способу определения позиции. Для демонстрации мы воспользуемся таблицей publication из схемы g11n.
DECLARE
v_instr NUMBER (2);
v_instrb NUMBER (2);
v_instrc NUMBER (2);
v_instr2 NUMBER (2);
v_instr4 NUMBER (2);
BEGIN
SELECT INSTR (title, 'グ'),
INSTRB (title, 'グ'),
INSTRC (title, 'グ
'),
INSTR2 (title, 'グ'),
INSTR4 (title, 'グ
')
INTO v_instr, v_instrb, v_instrc,
v_instr2, v_instr4
FROM publication
WHERE publication_id = 2;
DBMS_OUTPUT.put_line ('INSTR of グ: ' || v_instr);
DBMS_OUTPUT.put_line ('INSTRB of グ: ' || v_instrb);
DBMS_OUTPUT.put_line ('INSTRC of グ: ' || v_instrc);
DBMS_OUTPUT.put_line ('INSTR2 of グ: ' || v_instr2);
DBMS_OUTPUT.put_line ('INSTR4 of グ: ' || v_instr4);
END;
/
Результат:
INSTR of グ: 16
INSTRB of グ: 20
INSTRC of グ: 16
INSTR2 of グ: 16
INSTR4 of グ: 16
Позиция символа У отличается только для INSTRB. Одна из полезных особенностей INSTR2 и INSTR4 заключается в том, что они могут использоваться для поиска кодовых точек, не представляющих полные символы. Возвращаясь к примеру с символом А, умляут можно включить как подстроку для выполнения поиска.
LENGTH/LENGTHB/LENGTHC/LENGTH2/LENGTH4
Функции LENGTH возвращают длину строки в разных единицах:
LENGTH — возвращает длину строки в символах;
LENGTHB — возвращает длину строки в байтах;
LENGTHC — возвращает длину строки в символах Юникода;
LENGTH2 — возвращает количество кодовых единиц в строке;
LENGTH4 — возвращает количество кодовых точек в строке.
Если строка состоит из композиционных символов, функция LENGTH эквивалентна LENGTHC.
DECLARE
v_length NUMBER (2);
v_lengthb NUMBER (2);
v_lengthc NUMBER (2);
v_length2 NUMBER (2);
v_length4 NUMBER (2);
BEGIN
SELECT LENGTH (title), LENGTHB (title), lengthc (title), length2 (title),
length4 (title)
INTO v_length, v_lengthb, v_lengthc, v_length2,
v_length4
FROM publication
WHERE publication_id = 2;
DBMS_OUTPUT.put_line ('LENGTH of string: ' || v_length);
DBMS_OUTPUT.put_line ('LENGTHB of string: ' || v_lengthb);
DBMS_OUTPUT.put_line ('LENGTHC of string: ' || v_lengthc);
DBMS_OUTPUT.put_line ('LENGTH2 of string: ' || v_length2);
DBMS_OUTPUT.put_line ('LENGTH4 of string: ' || v_length4);
END;
Результат:
LENGTH of string: 28
LENGTHB of string: 52
LENGTHC of string: 28
LENGTH2 of string: 28
LENGTH4 of string: 28
В данном примере только функция LENGTHB дает другой результат. Как и ожидалось, LENGTH и LENGTHC вернули одинаковые результаты. Впрочем, при работе с декомпозиционными символами ситуация меняется. Пример:
DECLARE
v_length NUMBER (2);
BEGIN
SELECT LENGTH (UNISTR ('A308'))
INTO v_length
FROM DUAL;
DBMS_OUTPUT.put_line ('Decomposed string size using LENGTH: ' || v_length);
SELECT lengthc (UNISTR ('A308'))
INTO v_length
FROM DUAL;
DBMS_OUTPUT.put_line ('Decomposed string size using LENGTHC: ' || v_length);
END;
Функции возвращают следующие значения длины:
Decomposed string size using LENGTH: 2
Decomposed string size using LENGTHC: 1
Функция LENGTH возвращает количество символов, но считает A и умляут разными символами. LENGTHC возвращает длину в символах Юникода и видит только один символ.
SUBSTR/SUBSTRB/SUBSTRC/SUBSTR2/SUBSTR4
Разные версии SUBSTR определяются по тому же принципу, что и их аналоги у функций INSTR с LENGTH. SUBSTR возвращает часть строки заданной длины начиная с заданной позиции. Функции этого семейства работают следующим образом:
SUBSTR — определяет позицию и длину по символу;
SUBSTRB — определяет позицию и длину в байтах;
SUBSTRC — определяет позицию и длину в символах Юникода;
SUBSTR2 — использует кодовые единицы;
SUBSTR4 — использует кодовые точки.
Использование этих функций продемонстрировано в следующем примере:
DECLARE
v_substr VARCHAR2 (20);
v_substrb VARCHAR2 (20);
v_substrc VARCHAR2 (20);
v_substr2 VARCHAR2 (20);
v_substr4 VARCHAR2 (20);
BEGIN
SELECT SUBSTR (title, 13, 4), SUBSTRB (title, 13, 4),
substrc (title, 13, 4), substr2 (title, 13, 4),
substr4 (title, 13, 4)
INTO v_substr, v_substrb,
v_substrc, v_substr2,
v_substr4
FROM publication
WHERE publication_id = 2;
DBMS_OUTPUT.put_line ('SUBSTR of string: ' || v_substr);
DBMS_OUTPUT.put_line ('SUBSTRB of string: ' || v_substrb);
DBMS_OUTPUT.put_line ('SUBSTRC of string: ' || v_substrc);
DBMS_OUTPUT.put_line ('SUBSTR2 of string: ' || v_substr2);
DBMS_OUTPUT.put_line ('SUBSTR4 of string: ' || v_substr4);
END;
Обратите внимание на отличие SUBSTRB от других функций в результатах выполнения сценария:
SUBSTR of string: Lプログ
SUBSTRB of string: Lプ
SUBSTRC of string: Lプログ
SUBSTR2 of string: Lプログ
SUBSTR4 of string: Lプログ
UNISTR
Функция UNISTR преобразует строку в Юникод. Эта функция использовалась в ряде предыдущих примеров для вывода символов строки, подвергнутой декомпозиции. В разделе «Кодировка символов» в качестве примера была приведена строка, состоящая из кодовых пунктов. Чтобы привести ее к понятному виду, можно воспользоваться функцией UNISTR:
DECLARE
v_string VARCHAR2 (20);
BEGIN
SELECT UNISTR ('05307406507606506E')
INTO v_string
FROM DUAL;
DBMS_OUTPUT.put_line (v_string);
END;
Результат:
Steven