Если в коде PL/SQL используются строки как фиксированной (CHAR
), так и переменной (VARCHAR2
) длины, программист должен учитывать особенности выполнения в базе данных Oracle операций, в которых участвуют оба типа строк.
Перенос информации из базы данных в переменную
При выборке (SELECT
или FETCH
) данных из столбца базы данных типа CHAR
и присваивании их переменной типа VARCHAR2
завершающие пробелы сохраняются. Если же перенести данные из столбца типа VARCHAR2
в переменную типа CHAR
, PL/SQL автоматически дополнит извлекаемое значение пробелами до максимальной длины переменной. Таким образом, итоговое значение переменной определяется ее типом, а не типом столбца.
Перенос информации из переменной в базу данных
Когда вы помещаете (INSERT
или UPDATE
) значение переменной типа CHAR
в столбец базы данных типа VARCHAR2
, ядро SQL не подавляет завершающие пробелы. Например, при выполнении следующего кода PL/SQL столбцу company_name
базы данных присваивается значение ACME SHOWERS
........ (где символ «.» обозначает пробел). Иначе говоря, столбец дополняется пробелами до 20 символов, хотя исходным значением была строка из 12 символов.
DECLARE comp_id# NUMBER; comp_name CHAR(20) := 'ACME SHOWERS'; BEGIN SELECT company_id_seq.NEXTVAL INTO comp_id# FROM dual; INSERT INTO company (company_id, company_name) VALUES (comp_id#, comp_name); END;
С другой стороны, при помещении значения переменной типа VARCHAR2
в столбец базы данных типа CHAR
ядро SQL автоматически дополняет строку переменной длины пробелами до максимальной длины столбца (заданной при создании таблицы) и записывает результат в базу данных.
Сравнения строк
Предположим, некоторая программа содержит следующий оператор сравнения строк:
IF company_name = parent_company_name ...
PL/SQL должен сравнить значения company_name
и parent_company_name
. Эта операция выполняется одним из двух способов в зависимости от типов переменных:
- При сравнении двух переменных типа
CHAR
PL/SQL дополняет их завершающими пробелами. - Если хотя бы одна из строк имеет переменную длину, PL/SQL выполняет сравнение без дополнения завершающими пробелами.
Различие между этими двумя методами сравнения продемонстрировано в следующем фрагменте кода:
DECLARE company_name CHAR(30) := 'Feuerstein and Friends'; char_parent_company_name CHAR(35) := 'Feuerstein and Friends'; varchar2_parent_company_name VARCHAR2(35) := 'Feuerstein and Friends'; BEGIN -- Сравниваются два значения CHAR, строки дополняются пробелами IF company_name = char_parent_company_name THEN DBMS_OUTPUT.PUT_LINE ('Результат первой проверки равен TRUE'); ELSE DBMS_OUTPUT.PUT_LINE ('Результат первой проверки равен FALSE'); END IF; -- Сравниваются CHAR и VARCHAR2, поэтому строки не дополняются пробелами IF company_name = varchar2_parent_company_name THEN DBMS_OUTPUT.PUT_LINE ('Результат второй проверки равен TRUE'); ELSE DBMS_OUTPUT.PUT_LINE ('Результат второй проверки равен FALSE'); END IF; END
Результат:
Результат первой проверки равен TRUE Результат второй проверки равен FALSE
В первом сравнении участвуют два значения типа CHAR
, поэтому используется дополнение завершающими пробелами: PL/SQL дополняет более короткое из двух значений до длины более длинного значения, после чего они сравниваются. В данном примере PL/SQL добавляет пять пробелов в конец значения переменной company_name
, а затем сравнивает значения company_name
и char_parent_company_name
.
Проверка дает положительный результат. Обратите внимание: PL/SQL не изменяет значение переменной company_name
. Это значение просто копируется в другую структуру памяти, где оно модифицируется для сравнения.
Во второй операции участвуют значения типов CHAR
и VARCHAR2
, поэтому PL/SQL выполняет сравнение без дополнения завершающими пробелами. Ни одно из значений не изменяется, а в сравнении используется их текущая длина. В данном случае первые 22 символа обеих строк одинаковы (Feuerstein and Friends), но значение переменной фиксированной длины company_name
дополнено восемью пробелами, а значение переменной varchar2_parent_company_name
— нет. В результате строки оказываются не равными.
Участие в проверке значения типа VARCHAR2
приводит к тому, что сравнение выполняется без дополнения завершающими пробелами. Это верно и для выражений, содержащих более двух переменных, а также для выражений с оператором IN
. Пример:
IF menu_selection NOT IN (save_and_close, cancel_and_exit, 'OPEN_SCREEN') THEN ...
Если хотя бы одна из четырех строк (menu_selection
, две именованные константы и один литерал) объявлена как VARCHAR2
, точное сравнение будет выполнено без модификации значений. Обратите внимание: строковые литералы (такие, как OPEN_SCREEN
) всегда рассматриваются как строки фиксированной длины, то есть CHAR
.