Записки жертвы высоких технологий

    Здравствуйте! Мой блог посвящен в большей своей части моей профессиональной деятельности на поприще использования технологий ORACLE для разработки баз данных OLTP и OLAP хранилищ данных. В заметках я периодически размещаю разнообразные SQL, PL/SQL и Java скрипты написанные мной и не только мной, ссылки на интересные источники в сети либо другую полезную информацию, которая каким либо образом касается моей работы с замечательными продуктами компании ORACLE.
    Вы можете связаться со мной по контактному емейлу, если у вас есть какие-либо вопросы, связанные с разработкой баз данных на основе продуктов ORACLE, буду рад помочь вам, если это будет в моих силах.

29 авг. 2013 г.

Определение границ слов с помощью регулярных выражений в PL/SQL

Пишу сейчас очередной генератор структуры БД из метаданных для своей организации.
Для первоначального заполнения структуры новой БД взяли, разумеется старую версию оной. Однако, в результате анализа структуры выяснилось, что мои предшественники вовсю пользовались зарезервированными словами типа LEVEL и DESC для именования столбцов таблиц. Надо при генерации БД это учитывать и заключать названия столбцов в двойные кавычки ("). Все бы ничего, но есть такой элемент структуры таблицы, как CHECK и в нем условие ограничения описано в виде SQL-выражения, например:

     TYPE_ID is not null

или

    Upper(Name)=Name

Каким образом обработать их?
Тум, ту-ру-руууум! Разумеется регулярными выражениями. Для этого мне нужно определить границы слов, чтоб не заменить случаем Unnamed в Un"name"d. К сожалению, регулярные выражения ORACLE не поддерживают операторы определения границ слова \< и \>, поэтому придется выполнить два дополнительных прохода по строке до и после замены, чтобы создать их самому. Самый глубоко вложенный regexp_replace реализует обрамление chr(2) вокруг всех символов, которые могут быть использованы для разделения искомых идентификаторов. Следующий regexp_replace производит нужную нам замену. Самый верхний regexp_replace восстанавливает первоначальный вид строки.


select 
    regexp_replace(
        regexp_replace(
            regexp_replace('"NAME" IS NULL OR UPPER(NAME)=UNNAMED_FUNC(NAME)', '([^[:alnum:]_$"])',chr(2) || '\1' || chr(2)),
            '(\s|'||chr(2)||'|^)NAME(\s|'||chr(2)||'||$)',
            '"NAME"'
        ),
        chr(2),
        null
    )
from dual

цветом показаны:
    обрабатываемое выражение
    искомая строка
    замещающая строка

Шаблон поиска (^[:alnum:]_$") учитывает все символы, которые могут входить в название идентификатора. Символ " - добавлен для того, чтобы идентификатор, уже обрамленный двойными кавычками, не множил их вокруг себя.

1 комментарий:

Roger комментирует...

Спасибо за статью! Подскажите, как изменится запрос, если искомая строка может содержать внутри себя пробел (состоять из нескольких слов)?