Такой родной (native) SQLИсточник: Interface Ltd Владимир Пржиялковский, преподаватель УКЦ Interface Ltd.
Признаюсь, что эта заметка запоздала. Идея написать ее возникла у меня в голове год назад, если не больше, но как-то все откладывалось. За это время тема native SQL несколько раз уже возникала в русскоязычных источниках: в статье Павла Лузанова, помещенной в Русском internet-журнале по Oracle, издаваемом московским представительством Oracle, и в одном (или нескольких) из трех internet-форумах по Oracle на русском языке. Тем не менее, руководствуясь эмпирикой, гласящей, что много информации об Oracle на нашем родном языке не бывает, рискну добавить в этот разговор о родном SQL и лепту от себя. Речь пойдет о динамическом SQL, без которого разработчику прожить, наверное, невозможно. Соизмеряя эти естественные желания пользователей со своими возможностями, фирма Oracle ввела в версии своего сервера 7.1 пакет DBMS_SQL. Если по каким-то причинам этот пакет оказался в вашей системе отсутствующим, его можно завести, воспользовавшись сценариями Dmbssql.sql (открытое описание интерфейса пакета) и Prvtsql.plb (зашифрованный текст тела пакета) в каталоге Rdbms\Admin. Несмотря на новшества более поздних версий его пока рано выбрасывать (об этом ниже), а кроме того он используется для целого ряда внутренних потребностей системы в большинстве конфигураций. Так вот, в версии 8.1 появился еще один способ работы с динамическим SQL, называемый в документации native SQL. В рамках этой заметки "первый" динамический SQL будет для краткости называться "пакетным", а "второй" - "встроенным". Появление встроенного динамического SQL вызвало у многих разработчиков реакцию, по внешним проявлениям сильно смахивающую на вздох облегчения. Причина станет ясна из следующей сравнительной иллюстрации. Сравнительный пример пакетного и встроенного динамического SQLДля иллюстрации пакетного (старого) способа работы динамического SQL можно воспользоваться готовым примером, имеющимся в тексте Dbmssql.sql. Чтобы можно было пользоваться широко известной таблицей сотрудников пользователя SCOTT, немного откорректируем и чуть упростим этот пример, так что в результате получится следующее: SQL> create or replace procedure copy(source in varchar2, Теперь можно создать проверочную таблицу и выполнить процедуру: SQL> CREATE TABLE emp1 AS SELECT ename, hiredate FROM emp WHERE 1=2; Выполнив SELECT * FROM emp1, можно убедиться, что все сотрудники скопировались. А вот какой пример могла бы поместить фирма Oracle рядом для иллюстрации использования встроенного SQL: SQL> create or replace procedure copynative(source in varchar2, Теперь можно обнулить нашу "табличку для битья" и запустить новую процедуру: SQL> TRUNCATE TABLE emp1; …И результат тот же. Не правда ли, отличия разительны? Обратите внимание, что несмотря на пропуск предложения EXCEPTION, второй текст функционально ничуть не уже первого. В данном случае он даже имеет дополнительную общность, так как не требует указания типа копируемых полей. Причем, если кому-то понравится возможность получения результирующего числа обработанных строк (использованная лишь формально в первом примере), то второй пример можно модифицировать так: SQL> create or replace function fcopynative(source in varchar2, Новые возможностиДля работы со встроенным динамическим SQL используются следующие конструкции: EXECUTE IMMEDIATE SQL_string Плюс три конструкции специально для работы с запросами, порождающими множественные результаты: OPEN { cursor_variable / :host_cursor_variable } FOR SQL_string Выглядит, хотя и сложее, чем в примере выше, но все еще проще, чем правила и конструкции DBMS_SQL. За дальнейшими подробностями можно обратиться к документации. Свойства старого и нового способаКакие особенности есть у старого и нового способа работы с динамическим SQL? Вот, что позволяет делать встроенный динамический SQL:
А вот, что позволяет делать исключительно пакетный динамический SQL:
Судите сами, что вас больше устроит. Но, отказываться от DBMS_SQL полностью, кажется, еще не время. Еще один маленький, но показательный примерВ заключение еще один сравнительный пример старого и нового способа выполнения динамического SQL. Он хорош тем, что (а) компактен и (б) утилитарен. Автор примера - Стивен Фойерстин . Допустим, мы хотим написать процедуру, динамически запускающую на выполнение указанное в виде текста SQL-предложение. Вот какое решение может быть для пакетного SQL: CREATE OR REPLACE PROCEDURE runddl (ddl_in IN VARCHAR2) /* Pre Oracle8i implementation */ IS cur INTEGER:= DBMS_SQL.OPEN_CURSOR; fdbk INTEGER; BEGIN DBMS_SQL.PARSE (cur, ddl_in, DBMS_SQL.NATIVE); fdbk := DBMS_SQL.EXECUTE (cur); DBMS_SQL.CLOSE_CURSOR (cur); EXCEPTION WHEN OTHERS THEN DBMS_OUTPUT.PUT_LINE ( 'RunDDL Failure on ' // ddl_in); DBMS_OUTPUT.PUT_LINE (SQLERRM); DBMS_SQL.CLOSE_CURSOR (cur); END; / А вот, какое решение может быть получено с помощью встроенного SQL: CREATE OR REPLACE PROCEDURE runddl81 (ddl_in IN VARCHAR2) AUTHID CURRENT_USER IS BEGIN EXECUTE IMMEDIATE ddl_in; END; / Заметим здесь еще одну конструкцию: AUTHID CURRENT_USER. Она позволяет запускать runddl81 любому пользователю при том, что будут соблюдаться именно его полномочия по работе с БД (об этом подробнее см. в "Новое в 8i: полномочия предъявителя в PL/SQL". То есть SCOTT может выдать EXEC runddl81(‘create table newone (rightnow DATE)’); И новая табличка заведется у него; когда же точно такое предложение выдаст DEMO, то появится таблица DEMO.NEWONE. Такую удобную процедуру имеет смысл дать в распоряжение всем разработчикам. |