За годы работы у меня скопилось множество различных готовых решений для часто возникающих задач. Про замысловатые вещи (генератор паролей и SQL для описания структуры таблиц) я уже писал, а в этой заметке собраны некоторые простые полезные SQL-запросы, тексты хранимых процедур и скрипты для Firebird, решающие различные задачи. С одной стороны, эти скрипты слишком короткие и простые, чтобы посвящать им отдельные статьи или заметки в блоге, с другой — они могут быть полезны не только мне, но и кому-нибудь ещё.
Оглавление
Форматирование даты в SQL-запросах Firebird
Постановка задачи
Как известно, при попытке произвести в SQL-запросе конкатенацию строки и даты Firebird преобразует дату в фиксированный формат YYYY-MM-DD (по международному стандарту ISO 8601), который в России не используется. Поэтому как раз для таких случаев я написал пару хранимых процедур, которые приводят дату к нужному формату.
Решение № 1 (простое, формат ГОСТ Р 6.30-2003)
Описание: эта хранимая процедура осуществляет форматирование даты в привычный для России и соответствующий отечественному стандарту ГОСТ Р 6.30-2003 вид DD.MM.YYYY.
Версия СУБД: поддерживается в СУБД Firebird 1.5 и выше.
Входные параметры:
A_DATE date— датаLEADING_ZERO smallint[0/1] — признак, нужно ли ставить лидирующий ноль, если день содержит всего одну цифру (1, по умолчанию — по ГОСТ) или нет (0), то есть если LEADING_ZERO = 1, то 1 января 2001 года выглядит как 01.01.2001 (по ГОСТ, так что годится для всех официальных документов), а если 0, то 1.01.2001 (используется в неофициальных текстах).
RESULT varchar(10)— отформатированная дата.
(select RESULT from DATE2STR('1.01.2015', 1)) = '01.01.2015';
(select RESULT from DATE2STR('09-07-15')) = '7.09.2015';
(select RESULT from DATE2STR('12/7/15', 1)) = '07.12.2015';
Комментарии: достоинством этого решения является его простота и эффективность, а недостатком — опять-таки простота: поддерживается только один жёстко заданный формат, а для любого другого нужно писать отдельную процедуру.
Текст процедуры (дважды щёлкните на нём мышью, чтобы выделить для копирования):
create or alter procedure DATE2STR (
A_DATE date,
LEADING_ZERO smallint = 1)
returns (
RESULT varchar(10))
as
declare variable D_YEAR smallint;
declare variable D_MONTH smallint;
declare variable D_DAY smallint;
begin
if (A_DATE is null) then
RESULT = null;
else
begin
D_YEAR = extract(year from A_DATE);
D_MONTH = extract(month from A_DATE);
D_DAY = extract(day from A_DATE);
if (coalesce(LEADING_ZERO, 0) = 1) then
RESULT = lpad(cast(D_DAY as varchar(2)), 2, '0');
else
RESULT = cast(D_DAY as varchar(2));
RESULT = RESULT || '.' || lpad(cast(D_MONTH as varchar(2)), 2, '0') || '.' || cast(D_YEAR as varchar(4));
suspend;
end
end
Решение № 2 (универсальное)
Описание: на вход эта процедура получает дату и строку формата, в которой буквы Y, M и D обозначают позицию для элементов даты (год, месяц, день) в различных видах (подробнее см. описание входных параметров ниже).
Версия СУБД: поддерживается в СУБД Firebird 2.1 и выше.
Входные параметры:
A_DATE date— датаFORMAT varchar(1000)— строка, содержащая шаблон форматирования даты. Заменяются следующие комбинации символов:D— день без лидирующего пробелаDD— день с лидирующим пробеломDDD— день недели, краткое названиеDDDD— день недели, длинное названиеM— месяц без лидирующего пробелаMM— месяц с лидирующим пробеломMMM— месяц, краткое названиеMMMM— месяц, полное названиеYY— год, 2 последние цифрыYYYY— год, 4 цифры.
LONG_DAY_NAMES varchar(100)— полные названия дней недели через запятую (с понедельника по воскресенье)SHORT_DAY_NAMES varchar(50)— сокращённые названия дней недели через запятуюLONG_MONTH_NAMES varchar(200)— полные названия месяцев через запятуюSHORT_MONTH_NAMES varchar(200)— сокращённые названия месяцев через запятую
RESULT varchar(1000)— отформатированная дата.
(select RESULT from FORMAT_DATE('1.01.2015', 'D MMMM YYYY')) = '1 января 2015';
(select RESULT from FORMAT_DATE('7.09.2015', 'год YY от начала нынешнего столетия, день D MMMM месяца')) = 'год 15 от начала нынешнего столетия, день 7 сентября месяца';
(select RESULT from FORMAT_DATE('7.09.2015', 'M месяц года называется "MMMM" (сокращённо "MMM")', 'январь,февраль,март,апрель,май,июнь,июль,август,сентябрь,октябрь,ноябрь,декабрь') = '9 месяц года называется "сентябрь (сокращённо "сен")';
(select RESULT from FORMAT_DATE() = '7.09.2015' -- (зависит от текущей даты)
Комментарии: достоинством этого решения является его универсальность, а недостатком — сложность и низкая скорость выполнения.
Текст процедуры (дважды щёлкните на нём мышью, чтобы выделить для копирования):
create or alter procedure FORMAT_DATE (
A_DATE date = current_date,
FORMAT varchar(1000) = 'D.MM.YYYY',
LONG_DAY_NAMES varchar(100) = 'понедельник,вторник,среда,четверг,пятница,суббота,воскресенье',
SHORT_DAY_NAMES varchar(50) = 'пн,вт,ср,чт,пт,сб,вс',
LONG_MONTH_NAMES varchar(200) = 'января,февраля,марта,апреля,мая,июня,июля,августа,сентября,октября,ноября,декабря',
SHORT_MONTH_NAMES varchar(200) = 'янв,фев,мар,апр,мая,июн,июл,авг,сен,окт,ноя,дек')
returns (
RESULT varchar(1000))
as
declare variable D_YEAR smallint;
declare variable D_MONTH smallint;
declare variable D_DAY smallint;
declare variable M smallint;
declare variable D smallint;
declare variable L smallint;
declare variable S smallint;
declare variable L_MONTH varchar(15);
declare variable S_MONTH varchar(10);
declare variable L_DAY varchar(15);
declare variable S_DAY varchar(10);
begin
if (A_DATE is null) then
RESULT = null;
else
begin
D_YEAR = extract(year from A_DATE);
D_MONTH = extract(month from A_DATE);
D_DAY = extract(day from A_DATE);
RESULT = FORMAT;
if (FORMAT is null) then
RESULT = D_DAY || '.' || lpad(cast(D_MONTH as varchar(2)), 2, '0') || '.' || D_YEAR;
else
begin
RESULT = replace(replace(RESULT, 'YYYY', D_YEAR), 'YY', mod(extract(year from current_date), 100));
S_MONTH = '';
L_MONTH = '';
if (RESULT like '%MMM%') then
begin
M = D_MONTH;
while (M > 0) do
begin
L = position(',', LONG_MONTH_NAMES);
S = position(',', SHORT_MONTH_NAMES);
if (M = 1) then
begin
L_MONTH = substring(LONG_MONTH_NAMES from 1 for L - 1);
S_MONTH = substring(SHORT_MONTH_NAMES from 1 for S - 1);
end
else
begin
LONG_MONTH_NAMES = substring(LONG_MONTH_NAMES from L + 1);
SHORT_MONTH_NAMES = substring(SHORT_MONTH_NAMES from S + 1);
end
M = M - 1;
end
RESULT = replace(replace(RESULT, 'MMMM', coalesce(L_MONTH, '')), 'MMM', coalesce(S_MONTH, ''));
end
if (RESULT like '%DDD%') then
begin
D = coalesce(nullif(extract(weekday from A_DATE), 0), 7);
while (D > 0) do
begin
L = position(',', LONG_DAY_NAMES);
S = position(',', SHORT_DAY_NAMES);
if (D = 1) then
begin
L_DAY = substring(LONG_DAY_NAMES from 1 for L - 1);
S_DAY = substring(SHORT_DAY_NAMES from 1 for S - 1);
end
else
begin
LONG_DAY_NAMES = substring(LONG_DAY_NAMES from L + 1);
SHORT_DAY_NAMES = substring(SHORT_DAY_NAMES from S + 1);
end
D = D - 1;
end
RESULT = replace(replace(RESULT, 'DDDD', coalesce(L_DAY, '')), 'DDD', coalesce(S_DAY, ''));
end
RESULT = replace(RESULT, 'MM', lpad(cast(D_MONTH as varchar(2)), 2, '0'));
RESULT = replace(RESULT, 'M', D_MONTH);
RESULT = replace(RESULT, 'DD', lpad(cast(D_DAY as varchar(2)), 2, '0'));
RESULT = replace(RESULT, 'D', D_DAY);
end
end
suspend;
end
Перевод чисел в 16-ричную систему счисления на Firebird SQL
Постановка задачи
Дано целое число. Требуется получить его представление в шестнадцатеричной системе счисления.
Решение
Описание: на вход эта процедура получает число и минимальную длину, до которой этот получившийся результат нужно дополнить нулями слева.
Версия СУБД: поддерживается в СУБД Firebird 2.1 и выше.
Входные параметры:
NUM integer— числоMIN_LENGTH smallint— минимальная длина числа.
RESULT varchar(8)— 16-ричное представление числа.
Примеры:
(select RESULT from INT2HEX(189)) = 'BD'; (select RESULT from INT2HEX(5949, 8) = '0000173D';
Комментарии: на выходе предполагается строка длиной 8, потому что в Firebird 2 и 3 тип
integer является 32-битным, то есть записывается не более чем восемью 16-ричными цифрами от 0 до FFFFFFFF. Если заменить тип integer на bigint, то длина параметра RESULT должна увеличиться ровно вдвое (а больше никаких изменений не требуется).Текст процедуры (дважды щёлкните на нём мышью, чтобы выделить для копирования):
create or alter procedure INT2HEX (
NUM integer,
MIN_LENGTH smallint = 0)
returns (
RESULT varchar(8))
as
begin
if (NUM is null) then
RESULT = null;
else
begin
RESULT = '';
while (NUM > 0) do
begin
RESULT = decode(mod(NUM, 16), 15, 'F', 14, 'E', 13, 'D', 12, 'C', 11, 'B', 10, 'A', mod(NUM, 16)) || RESULT;
NUM = NUM / 16;
end
if (MIN_LENGTH > 0) then
RESULT = lpad(RESULT, MIN_LENGTH, '0');
end
suspend;
end
Преобразование списка, переданного в виде строки элементов, в таблицу
Постановка задачи
Дан список элементов, переданный в виде строки. Нужно получить этот же список в виде таблицы.
Зачем это нужно: иногда возникают такие ситуации, когда нужно передать в запрос переменное или неизвестное заранее количество параметров. Например (это очень сильно упрощённый пример!): дана таблица, содержащая два поля, ID (код) и NAME (название). Нам нужно выбрать из неё строки с определёнными конкретными кодами, количество которых заранее неизвестно. Мы можем выразить это так:
select
ID,
NAME
from
MY_TABLE
where
ID = any(select
LIST_ITEM
from
SPLIT(:ID_LIST))
Теперь можно передать в этот запрос строку, содержащую список кодов через запятую.
Решение
Описание: на вход эта процедура получает саму строку и разделитель элементов. Фактически она делает преобразование, обратное к действию агрегатной функции list.
Версия СУБД: поддерживается в СУБД Firebird 1.5 и выше.
Входные параметры:
DELIMITED_LIST varchar(1000)— список в виде строкиMIN_LENGTH varchar(10)— разделитель элементов списка.
LIST_NUM smallint— порядковый номер элемента (если 0, то список пустой),LIST_ITEM varchar(1000)— очередной элемент списка.
Комментарии: важно отметить, что эта процедура не производит полноценный парсинг строки и не умеет распознавать экранированные разделители, как это делают многие языки программирования. Хотя её не так уж сложно доработать для этого.
Текст процедуры (дважды щёлкните на нём мышью, чтобы выделить для копирования):
create or alter procedure SPLIT (
DELIMITED_LIST varchar(1000),
DELIMITER varchar(10) = ',')
returns (
LIST_NUM smallint,
LIST_ITEM varchar(1000))
as
declare variable I smallint;
begin
LIST_NUM = 0;
if (DELIMITED_LIST is null or DELIMITED_LIST || '.' = '.') then
/* сравнивать с пустой строкой напрямую в SQL нельзя, т.к. игнорируются хвостовые пробелы,
см. спецификацию ANSI/ISO SQL-92, раздел 8.2 */
begin
LIST_ITEM = DELIMITED_LIST;
suspend;
end
else
while (DELIMITED_LIST || '.' <> '.') do
begin
if (DELIMITER is null or DELIMITER || '.' = '.') then
begin
LIST_ITEM = substring(DELIMITED_LIST from 1 for 1);
DELIMITED_LIST = substring(DELIMITED_LIST from 2);
end
else
begin
I = position(DELIMITER in DELIMITED_LIST);
if (I = 0) then
begin
LIST_ITEM = DELIMITED_LIST;
DELIMITED_LIST = '';
end
else
begin
LIST_ITEM = substring(DELIMITED_LIST from 1 for I - 1);
DELIMITED_LIST = substring(DELIMITED_LIST from I + char_length(DELIMITER));
end
end
LIST_NUM = LIST_NUM + 1;
suspend;
end
end
Склонение размерности единиц измерения при числительных
Постановка задачи
Дано целое число и название размерности («рубль», «килограмм» и т. п.). Требуется выбрать правильный падеж и число для размерности, чтобы они соответствовали переданному значению: «1 рубль», «3 рубля», «15 рублей».
Решение № 1 (Firebird 2.1 и старше)
Описание: на вход эта процедура получает число и название единицы измерения в разных падежах и числах, а возвращает выбранный в зависимости от значения вариант.
Отмечу, что в действительности процедура здесь и не нужна, потому что состоит она из единственной строки. Если она нужна всего один-два раза, то можно просто взять эту строку и скопировать в свои запросы.
Отмечу, что в действительности процедура здесь и не нужна, потому что состоит она из единственной строки. Если она нужна всего один-два раза, то можно просто взять эту строку и скопировать в свои запросы.
Версия СУБД: поддерживается в СУБД Firebird 2.1 и выше.
Входные параметры:
NUM integer— числоTITLE0 varchar(100)— именительный падеж размерности, единственное число (например, «рубль», «день»)TITLE1 varchar(100)— родительный падеж размерности, единственное число (например, «рубля», «дня»)TITLE2 varchar(100)— родительный падеж размерности, множественное число (например, «рублей», «дней»)
RESULT varchar(100)— название размерности в нужном падеже и числе.
Примеры:
(select RESULT from DECL_OF_NUM(213, 'день', 'дня', 'дней')) = 'дней'; (select RESULT from DECL_OF_NUM(42, 'рубль', 'рубля', 'рублей') = 'рубля';
Комментарии: как и в случае с переводом даты в строку (см. выше) эта процедура может показаться примитивной, но она оказывается полезной при форматировании строк.
Текст процедуры (дважды щёлкните на нём мышью, чтобы выделить для копирования):
create or alter procedure DECL_OF_NUM (
NUM integer,
TITLE0 varchar(100),
TITLE1 varchar(100),
TITLE2 varchar(100))
returns (
RESULT varchar(100))
as
begin
RESULT = iif(mod(NUM, 100) > 4 and mod(NUM, 100) < 20 or
mod(NUM, 10) >= 5, TITLE2, decode(mod(NUM, 10), 0, TITLE2, 1,
TITLE0, 2, TITLE1, 3, TITLE1, 4, TITLE1));
suspend;
end
Решение № 2 (Firebird 1.0)
Описание: на вход эта процедура получает число и название единицы измерения в разных падежах и числах, а возвращает выбранный в зависимости от значения вариант.
Версия СУБД: поддерживается в СУБД Firebird 1.0 и выше.
Входные параметры:
NUM integer— числоTITLE0 varchar(100)— именительный падеж размерности, единственное число (например, «рубль», «день»)TITLE1 varchar(100)— родительный падеж размерности, единственное число (например, «рубля», «дня»)TITLE2 varchar(100)— родительный падеж размерности, множественное число (например, «рублей», «дней»)
RESULT varchar(100)— название размерности в нужном падеже и числе.
Примеры:
(select RESULT from DECL_OF_NUM(213, 'день', 'дня', 'дней')) = 'дней'; (select RESULT from DECL_OF_NUM(42, 'рубль', 'рубля', 'рублей') = 'рубля';
Комментарии: Это специальная версия процедуры для старых БД, в которых не поддерживаются нужные для предыдущего решения функции mod и decode. Вместо них тут формируется «виртуальная таблица», из которой выбирается нужное значение.
Текст процедуры (дважды щёлкните на нём мышью, чтобы выделить для копирования):
create or alter procedure DECL_OF_NUM (
NUM integer,
TITLE0 varchar(100),
TITLE1 varchar(100),
TITLE2 varchar(100))
returns (
RESULT varchar(100))
as
begin
if (NUM - NUM / 100 * 100 > 4 and NUM - NUM / 100 * 100 < 20 or NUM - NUM / 10 * 10 >= 5) then
RESULT = TITLE2;
else
select
NAME
from
(select
0 as ID,
:TITLE2 as NAME
from
RDB$DATABASE
union all
select
1 as ID,
:TITLE0 as NAME
from
RDB$DATABASE
union all
select
2 as ID,
:TITLE1 as NAME
from
RDB$DATABASE
union all
select
3 as ID,
:TITLE1 as NAME
from
RDB$DATABASE
union all
select
4 as ID,
:TITLE1 as NAME
from
RDB$DATABASE)
where
ID = :NUM - :NUM / 10 * 10
into
:RESULT;
suspend;
end
Поиск латинских букв в русских словах
Постановка задачи
Имеется столбец в таблице, который должен содержать только русские буквы (например, ФИО). Но программа для ввода данных не умеет фильтровать русские и латинские буквы, из-за чего иногда русские буквы оказываются заменены похожими латинскими (русская «о» или «а» визуально неотличима от латинской). Нужно, во-первых, найти все такие строки, во-вторых, визуально выделить в них подлежащую замене букву, в-третьих, заменить её на русскую.
Предупреждения: Во-первых, многое зависит от шрифта. Во-вторых, в примерах ниже проверяются буквы, которые визуально совпадают в обычном прямом начертании большинства традиционных шрифтов. В курсивном начертании некоторые пары букв будут другими, например, для шрифтов Arial и Times New Roman добавляются строчная латинская «u» (u) и русская «и» (и) или строчная латинская «m» (m) и русская строчная «т» (т). В прямом начертании эти буквы в большинстве шрифтов совсем не похожи. Не похожи они и в курсиве шрифта Ubuntu, который используется в десктопной версии этого блога.
Предупреждения: Во-первых, многое зависит от шрифта. Во-вторых, в примерах ниже проверяются буквы, которые визуально совпадают в обычном прямом начертании большинства традиционных шрифтов. В курсивном начертании некоторые пары букв будут другими, например, для шрифтов Arial и Times New Roman добавляются строчная латинская «u» (u) и русская «и» (и) или строчная латинская «m» (m) и русская строчная «т» (т). В прямом начертании эти буквы в большинстве шрифтов совсем не похожи. Не похожи они и в курсиве шрифта Ubuntu, который используется в десктопной версии этого блога.
Решение № 1 (запрос, «функциональный» стиль)
Описание: простой запрос, в который нужно подставить имена таблицы и поля.
Версия СУБД: поддерживается в СУБД Firebird 2.1 и выше.
Входные параметры: нет.
Возвращаемые значения зависят от структуры таблицы. Я для примера использовал простую таблицу с двумя полями: ID (первичный ключ) и NAME (наименование, в котором мы ищем латинские буквы).
ID integer— первичный ключ таблицыBAD_NAME varchar(...)(размерность зависит от размерности поля NAME) — поле NAME, в котором латинские буквы выделены квадратными скобками, чтобы сразу их увидетьGOOD_NAME varchar(...)(размерность зависит от размерности поля NAME) — поле NAME, в котором латинские буквы заменены на похожие русские.
Комментарии: достоинством этого решения является то, что оно заметно короче и чуть быстрее работает, чем второе. Недостатки: во-первых, трудно воспринимается человеком, во-вторых, если понадобится добавить символ, то это не очень удобно делать.
Текст запроса (дважды щёлкните на нём мышью, чтобы выделить для копирования):
select ID, replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(NAME, 'T', '[T]'), 'K', '[K]'), 'H', '[H]'), 'M', '[M]'), 'B', '[B]'), 'C', '[C]'), 'X', '[X]'), 'A', '[A]'), 'P', '[P]'), 'O', '[O]'), 'E', '[E]'), 'c', '[c]'), 'y', '[y]'), 'p', '[p]'), 'x', '[x]'), 'e', '[e]'), 'a', '[a]'), 'o', '[o]') as BAD_NAME, replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(NAME, 'T', 'Т'), 'K', 'К'), 'H', 'Н'), 'M', 'М'), 'B', 'В'), 'C', 'С'), 'X', 'Х'), 'A', 'А'), 'P', 'Р'), 'O', 'О'), 'E', 'Е'), 'c', 'с'), 'y', 'у'), 'p', 'р'), 'x', 'х'), 'e', 'е'), 'a', 'а'), 'o', 'о') as GOOD_NAME from MY_TABLE where NAME similar to '%[eyopaxcTKHMBEOPAXC]+%'
Вариант: если нам непременно нужно «выловить» спрятанные среди кириллицы латинские буквы (то есть текст не содержит слов, полностью набранных латинскими буквами), то регулярное выражение усложняется:
select ID, replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(NAME, 'T', '[T]'), 'K', '[K]'), 'H', '[H]'), 'M', '[M]'), 'B', '[B]'), 'C', '[C]'), 'X', '[X]'), 'A', '[A]'), 'P', '[P]'), 'O', '[O]'), 'E', '[E]'), 'c', '[c]'), 'y', '[y]'), 'p', '[p]'), 'x', '[x]'), 'e', '[e]'), 'a', '[a]'), 'o', '[o]') as BAD_NAME, replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(NAME, 'T', 'Т'), 'K', 'К'), 'H', 'Н'), 'M', 'М'), 'B', 'В'), 'C', 'С'), 'X', 'Х'), 'A', 'А'), 'P', 'Р'), 'O', 'О'), 'E', 'Е'), 'c', 'с'), 'y', 'у'), 'p', 'р'), 'x', 'х'), 'e', 'е'), 'a', 'а'), 'o', 'о') as GOOD_NAME from MY_TABLE where NAME similar to '(%([[:WHITESPACE:]]|[^[:ALPHA:]]))?[eyopaxcTKHMBEOPAXC]+(([[:WHITESPACE:]]|[^[:ALPHA:]])%)?'
Решение № 2 (блок, «процедурный» стиль)
Описание: блок, в который также нужно подставить имена таблицы и поля.
Версия СУБД: поддерживается в СУБД Firebird 2.1 и выше.
Входные параметры: нет.
Возвращаемые значения зависят от структуры таблицы. Я для примера использовал простую таблицу с двумя полями: ID (первичный ключ) и NAME (наименование, в котором мы ищем латинские буквы).
ID integer— первичный ключ таблицыBAD_NAME varchar(...)(размерность зависит от размерности поля NAME) — поле NAME, в котором латинские буквы выделены квадратными скобками, чтобы сразу их увидетьGOOD_NAME varchar(...)(размерность зависит от размерности поля NAME) — поле NAME, в котором латинские буквы заменены на похожие русские.
Комментарии: достоинством этого решения является то, что оно легко читается и здесь легко добавить или убрать любую пару похожих символов (они компактно собраны в одном месте). Недостатки: размер стал заметно больше, медленнее работает на больших таблицах.
Текст запроса (дважды щёлкните на нём мышью, чтобы выделить для копирования):
execute block
returns (
ID type of column MY_TABLE.ID,
BAD_NAME type of column MY_TABLE.NAME,
GOOD_NAME type of column MY_TABLE.NAME)
as
declare variable LETTERS varchar(26);
declare variable REPLACEMENTS varchar(26);
declare variable LETTER_COUNT smallint;
declare variable I smallint;
declare variable C char(1);
begin
LETTERS = 'eyopaxcEOPAHKXCBM';
REPLACEMENTS = 'еуорахсЕОРАНКХСВМ';
LETTER_COUNT = char_length(LETTERS);
for select
ID,
NAME
from
MY_TABLE
where
NAME similar to '%[' || :LETTERS || ']+%'
/* '(%([[:WHITESPACE:]]|[^[:ALPHA:]]))?[' || :LETTERS || ']+(([[:WHITESPACE:]]|[^[:ALPHA:]])%)?'
для поиска «спрятанных» среди кириллицы букв */
into
:ID,
:BAD_NAME
do
begin
GOOD_NAME = BAD_NAME;
I = 1;
while (I <= LETTER_COUNT) do
begin
C = substring(LETTERS from I for 1);
BAD_NAME = replace(BAD_NAME, C, '[' || C || ']');
GOOD_NAME = replace(GOOD_NAME, C, substring(REPLACEMENTS from I for 1));
I = I + 1;
end
suspend;
end
end
Комментариев нет:
Отправить комментарий
Пожалуйста, не используйте в сообщениях ненормативную лексику и нарушающие закон темы