До разработки стандарта Юникод существовало множество схем кодировки, которые обладали ограниченными возможностями, а порой и конфликтовали друг с другом. Разработка глобальных приложений по единым правилам была практически невозможна, потому что ни одна кодировка не поддерживала все символы.
Стандарт Юникод решает все эти проблемы. Он разрабатывается и сопровождается Консорциумом Юникода. Содержимое каждой версии определяется Стандартом Юникода и Базой данных символов Юникода, или USD
(Unicode Character Database).
Набор символов Юникода позволяет хранить и извлекать данные в более чем 200 различных отдельных наборах. Использование набора символов Юникода обеспечивает поддержку всех этих наборов без внесения архитектурных изменений в приложение.
-
Oracle11g Release 2
поддерживает Юникод версии 5.0. Этот стандарт, впервые опубликованный в 2006 году, обеспечивает кодирование более одного миллиона символов. Этого достаточно для поддержки всех современных символов, а также многих древних или малораспространенных алфавитов.Oracle
Database 12c
включает поддержку Юникода 6.1 (стандарт опубликован в январе 2012 г.) и вводит несколько новых лингвистических порядков сопоставления, соответствующих правиламUCA
(Unicode Conation Algorithm). - Наборы символов Юникода в
Oracle11g
включают кодировкиUTF-8
иUTF-16
. ВUTF-8
для представления символа используется 1, 2 или 3 байта в зависимости от символа. ВUTF-16
символ всегда представляется двумя байтами. В обеих схемах поддерживаются дополнительные символы, использующие 4-байтовое представление независимо от выбранного набора символов Юникода. - Наборы символов Юникода в
Oracle Database 11g
и 12c включают кодировкиUTF-8
иUTF-16
. ВUTF-8
символы представляются 1, 2 или 3 байтами в зависимости от символа. ВUTF-16
все символы представляются 2 байтами. Дополнительные символы поддерживаются обеими кодировками и представляются 4 байтами на символ независимо от выбранной кодировки.
Каждая база данных Oracle
имеет два набора символов. Первичный набор символов используется для большинства функций приложений, а отдельный набор символов NLS
— для типов данных и функций, специфических для NLS
. Для определения используемых наборов символов используется следующий запрос:
SELECT parameter, VALUE
FROM nls_database_parameters
WHERE parameter IN ('NLS_CHARACTERSET', 'NLS_NCHAR_CHARACTERSET')
В рабочей среде автора запрос возвращает следующий результат:
PARAMETER VALUE
------------------------- ----------
NLS_CHARACTERSET AL32UTF8
NLS_NCHAR_CHARACTERSET AL16UTF16
В данном случае параметр NLS_CHARACTERSET
(первичный набор символов базы данных) имеет значение AL32UTF8
. В этот 32-разрядный набор символов Юникода UTF-8
входит большинство самых распространенных символов в мире. Параметр NLS_NCHAR_ CHARACTERSET
, используемый прежде всего для столбцов NCHAR
и NVARCHAR2
, представляет собой 16-разрядный набор символов UTF-16
.
Структура имен, присваиваемых наборам символов в Oracle
, содержит полезную информацию. Например, US7ASCII
поддерживает символы английского языка для США. Набор символов AL32UTF8
поддерживает любые языки. Вторая часть строки определяет количество битов на символ. В US7ASCII
символ представляется 7 битами, а AL32UTF8
использует до 32 бит на символ. Оставшаяся часть строки содержит «официальное» название набора символов. Структура имени представлена на рис. 1.
Рис. 1. Структура имени набора символов в Oracle
За дополнительной информацией о Юникоде обращайтесь на сайт Стандарта Юникод по адресу.
Типы данных и национальные наборы символов
Типы данных Globalization Support nclob
, nchar
и nvarchar2
используют набор символов, определяемый параметром nls_nchar_characterset
, — вместо набора символов по умолчанию, устанавливаемого для базы данных в параметре nls_characterset
. Эти типы данных поддерживают только многобайтовые символы Юникода, поэтому даже при работе с базой данных, в которой по умолчанию вместо Юникода используется другая кодировка, они будут хранить символы в национальном наборе символов. А так как национальный набор символов поддерживает только кодировки UTF-8
и UTF- 16
, NCLOB
, NCHAR
и NVARCHAR2
гарантированно будут хранить данные в многобайтовом Юникоде.
Прежде это создавало проблемы при сравнении столбцов nclob/nchar/nvarchar2
со столбцами clob/char/varchar2
. Во всех версиях, поддерживаемых в настоящее время, Oracle
выполняет автоматическое преобразование, благодаря которому становится возможным корректное сравнение.
Кодировка символов
Выбор набора символов во время создания базы данных определяет тип кодировки символов. Каждому символу ставится в соответствие код, уникальный для данного символа (кодовая точка). Это значение является частью таблицы отображения символов Юникода, содержимое которой находится под контролем Консорциума Юникода.
Кодовые точки состоят из префикса U+ (или обратной косой черты \
), за которым следует шестнадцатеричный код символа с диапазоном допустимых значений от U+0000
до U+10FFFF16
. Комбинированные символы (например, А
) могут разбиваться на компоненты (A с умляутом), а затем снова восстанавливаться в своем исходном состоянии. Скажем, декомпозиция А состоит из кодовых точек U+0041 (A)
и U+0308
(умляут). В следующем разделе будут рассмотрены некоторые функции Oracle
для работы с кодовыми точками.
Кодовой единицей (code unit
) называется размер в байтах типа данных, используемого для хранения символов. Размер кодовой единицы зависит от используемого набора символов. В некоторых обстоятельствах кодовая точка слишком велика для одной кодовой единицы, и для ее представления требуется несколько кодовых единиц.
Конечно, пользователи воспринимают символы, а не кодовые точки или кодовые единицы. «Слово» \0053\0074\0065\0076\0065\006E
вряд ли будет понятно среднему пользователю, который распознает символы на своем родном языке. Не забывайте, что глиф (изображение символа, непосредственно отображаемое на экране) является всего лишь представлением кодового пункта. Даже если на вашем компьютере не установлены необходимые шрифты или он по другим причинам не может вывести символы на экран, это вовсе не означает, что в Oracle
соответствующая кодовая точка хранится некорректно.
Параметры Globalization Support (NLS)
Поведение Oracle
по умолчанию определяется параметрами Globalization Support (NLS)
. Значения параметров, задаваемые при создании базы данных, определяют многие аспекты ее работы — от наборов символов до используемых по умолчанию денежных единиц. В табл. 1 перечислены параметры, которые вы можете изменить в ходе сеанса, с примерами значений и пояснениями. За текущими значениями параметров в вашей системе обращайтесь к представлению NLS_SESSI0N_PARAMETERS
.
Таблица 1. Сеансовые параметры NLS
Параметр | Описание | Пример |
NLS_CALENDAR | Задает календарь по умолчанию для базы данных | GREGORIAN |
NLS_COMP | В сочетании с NLS_SORT определяет правила сортировки символов. При использовании значения ANSI необходимо использовать лингвистический индекс | BINARY |
NLS_CURRENCY | Задает знак денежной единицы; по умолчанию определяется на основании NLS_TERRITORY | $ |
NLS_DATE_FORMAT | Задает формат даты; по умолчанию определяется на основании NLS_TERRITORY | DD-MON-RR |
NLS_DATE_LANGUAGE | Определяет способ записи дня и месяца для функций обработки дат | AMERICAN |
NLS_DUAL_CURRENCY | Упрощает поддержку евро; по умолчанию определяется на основании NLS_TERRITORY . Задает альтернативную денежную единицу для территории | $ |
NLS_ISO_CURRENCY | Символ денежной единицы ISO; по умолчанию определяется на основании NLS_TERRITORY | AMERICA |
NLS_LANGUAGE | Задает язык, используемый базой данных по умолчанию. Значение влияет на многие аспекты, от формата даты до сообщений сервера | AMERICAN |
NLS_LENGTH_SEMANTICS | Определяет используемую семантику длины (символы или байты) | BYTE |
NLS_NCHAR_CONV_EXCP | Определяет, должно ли выдаваться сообщение об ошибке при преобразовании символьного типа | FALSE |
NLS_NUMERIC_CHARACTERS | Определяет разделители дробной части и групп разрядов; по умолчанию определяется на основании NLS_TERRITORY | ., |
NLS_SORT | Определяет порядок сортировки символов для заданного языка | BINARY |
NLS_TERRITORY | Определяет значения по умолчанию многих параметров NLS . Значение определяет основной регион базы данных | AMERICA |
NLS_TIMESTAMP_FORMAT | Определяет формат временной метки по умолчанию для функций TO_TIMESTAMP и TO_CHAR | DD-MON-RR HH.MI.SSXF F AM |
NLS_TIMESTAMP_TZ_FORMAT | Определяет формат временной метки с часовым поясом для функций TO_TIMESTAMP и TO_CHAR | DD-MON-RR HH.MI.SSXF F AM TZR |
NLS_TIME_FORMAT | Используется в сочетании с NLS_DATE_FORMAT (см. выше). Задает формат времени по умолчанию для базы данных | HH.MI.SSXF F AM |
NLS_TIME_TZ_FORMAT | Определяет формат времени с часовым поясом или смещением UTC | HH.MI.SSXF F AM TZR |
Функции юникода
Поддержка Юникода в 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: \00C4
COMPOSE
Некоторые символы могут иметь несколько вариантов представления кодовых пунктов. Это создает проблемы при сравнении двух значений. Символ А может быть представлен как одним кодовым пунктом U+00C4
, так и двумя кодовыми пунктами U+0041
(буква A) и U+0308. При сравнении PL/SQL
считает, что эти два варианта представления не равны.
DECLARE
v_precomposed VARCHAR2 (20) := UNISTR ('\00C4');
v_decomposed VARCHAR2 (20) := UNISTR ('A\0308');
BEGIN
IF v_precomposed = v_decomposed
THEN
DBMS_OUTPUT.put_line ('==EQUAL==');
ELSE
DBMS_OUTPUT.put_line ('<>NOT EQUAL<>');
END IF;
END;
Результат:
<>NOT EQUAL<>
Однако после использования функции COMPOSE
эти две версии равны:
DECLARE
v_precomposed VARCHAR2 (20) := UNISTR ('\00C4');
v_decomposed VARCHAR2 (20) := COMPOSE (UNISTR ('A\0308'));
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) := 'A\0308';
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 ('A\0308'))
INTO v_length
FROM DUAL;
DBMS_OUTPUT.put_line ('Decomposed string size using LENGTH: ' || v_length);
SELECT lengthc (UNISTR ('A\0308'))
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 ('\0053\0074\0065\0076\0065\006E')
INTO v_string
FROM DUAL;
DBMS_OUTPUT.put_line (v_string);
END;
Результат:
Steven