В Oracle Database существует тип данных VARCHAR2, у которого можно указывать максимальную длину в скобках:
1 2 3 4 5 |
CREATE TABLE mytable ( ... myfield VARCHAR2(100) NOT NULL, ... ) |
В коде выше мы указали, что максимальная длина будет 100. Только вот 100 чего?
По умолчанию для VARCHAR2 длина указывается в байтах, то есть у нас будет максимальная длина равна 100 байт, а значит, в некоторых случаях там поместится меньше 100 символов, так как в Юникоде они могут занимать больше одного байта. Мы же, разумеется, хотим указывать длину именно в символах, а не в байтах. Что же делать?
К счастью, длину можно указывать и в символах. Для этого нужно явно писать размерность CHAR:
1 2 3 4 5 |
CREATE TABLE mytable ( ... myfield VARCHAR2(100 CHAR) NOT NULL, ... ) |
По умолчанию же используются байты, что равносильно принудительному указанию 100 BYTE:
1 2 3 4 5 |
CREATE TABLE mytable ( ... myfield VARCHAR2(100 BYTE) NOT NULL, ... ) |
Как я уже писал выше, если не указывать BYTE / CHAR, то по умолчанию считается, что используются байты, но это можно изменить.
В Oracle существует настройка NLS_LENGTH_SEMANTICS. Именно она указывает, в чём будет длина строки для случая, когда в VARCHAR2 явно не указано, использовать BYTE или CHAR.
Всего она существует на трёх уровнях:
- Для базы.
- Для экземпляра.
- Для сессии.
Значение для базы можно получить с помощью SQL:
1 2 3 |
SELECT value FROM NLS_DATABASE_PARAMETERS WHERE parameter='NLS_LENGTH_SEMANTICS'; |
Значение для экземпляра можно получить с помощью:
1 2 3 |
SELECT value FROM NLS_INSTANCE_PARAMETERS WHERE parameter='NLS_LENGTH_SEMANTICS'; |
Значение для текущей сессии:
1 2 3 |
SELECT value FROM NLS_SESSION_PARAMETERS WHERE parameter='NLS_LENGTH_SEMANTICS'; |
Значение для базы указывается только в момент создания базы и НЕ может изменяться в дальнейшем.
Значение для экземпляра сначала имеет такое же значение, что и значение для базы, но его можно изменить (но это крайне не рекомендуется делать). Я даже не буду здесь описывать процесс изменения значения для экземпляра, чтобы не давать плохую рекомендацию.
Значение для сессии имеет то же самое значение, что и значение для экземпляра, но его можно изменить через ALTER SESSION:
1 2 3 4 5 |
ALTER SESSION SET NLS_LENGTH_SEMANTICS=CHAR / SELECT value FROM NLS_SESSION_PARAMETERS where parameter='NLS_LENGTH_SEMANTICS' / |
Пока ничего страшного, всё хорошо. Однако проблема возникает, если мы не послушали официальную рекомендацию и установили значение NLS_LENGTH_SEMANTICS на уровне экземпляра. Некоторые клиенты действительно будут использовать это значение и не указывать своё, но SQL Developer согласно настройкам по умолчанию (это не ошибка, такое поведение описано в официальной документации) переопределяет значения для NLS_* на уровне сессии. Это всё указывается в Tools → Preferences…, затем в появившемя окне пункт Database → NLS. В этом диалоговом окне указаны значения, на которые будут переопределяться значения NLS_* для сессии:

В принципе, в этом есть здравый смысл, так как все опытные разработчики Oracle ожидают, что длина будет по умолчанию указываться в байтах. Однако если же вы действительно нарушили рекомендацию и изменили настройки для уровня экземпляра, то здесь вам придётся, скорее всего, поставить галочку на Skip NLS Settings, чтобы использовать их.
Полезно знать, что в Oracle Database отсутствует тип BOOLEAN для колонок таблиц.