<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	<title>Oracle PL/SQL</title>
	<atom:link href="http://osql.ru/?feed=rss2" rel="self" type="application/rss+xml" />
	<link>http://osql.ru</link>
	<description>Програмирование баз данных Oracle на языке PL/SQL</description>
	<lastBuildDate>Fri, 20 Nov 2009 13:57:55 +0000</lastBuildDate>
	<generator>http://wordpress.org/?v=2.8.4</generator>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
			<item>
		<title>Встроенный динамический SQL</title>
		<link>http://osql.ru/?p=113</link>
		<comments>http://osql.ru/?p=113#comments</comments>
		<pubDate>Fri, 20 Nov 2009 13:53:07 +0000</pubDate>
		<dc:creator>admin</dc:creator>
				<category><![CDATA[Встроенный динамический SQL]]></category>

		<guid isPermaLink="false">http://osql.ru/?p=113</guid>
		<description><![CDATA[Встроенный динамический SQL впервые появился в Oracle 8i. Он позволяет декла-
ративно выполнять динамический SQL в среде PL/SQL. Большинство действий можно
выполнить с помощью одного оператора, EXECUTE IMMEDIATE, а остальные — с по-
мощью оператора OPEN FOR. Оператор EXECUTE IMMEDIATE имеет следующий син-
таксис:
где:
• оператор — любой оператор SQL или PL/SQL-блок;
• переменная1, переменная2,&#8230; переменнаяN или запись — переменные PL/SQL, [...]]]></description>
			<content:encoded><![CDATA[<p>Встроенный динамический SQL впервые появился в Oracle 8i. Он позволяет декла-<br />
ративно выполнять динамический SQL в среде PL/SQL. Большинство действий можно<br />
выполнить с помощью одного оператора, EXECUTE IMMEDIATE, а остальные — с по-<br />
мощью оператора OPEN FOR. Оператор EXECUTE IMMEDIATE имеет следующий син-<br />
таксис:<br />
где:<br />
• оператор — любой оператор SQL или PL/SQL-блок;<br />
• переменная1, переменная2,&#8230; переменнаяN или запись — переменные PL/SQL, в<br />
которые необходимо выбрать данные (столбцы одной строки результатов опера-<br />
тора SELECT);<br />
• связываемая_переменная1,&#8230; связываемая переменнаяN — набор переменных PL/<br />
SQL, используемых для передачи входных данных/результатов;<br />
• результат1, &#8230; результатN — набор PL/SQL-переменных, используемых для раз-<br />
мещения результатов, возвращаемых конструкцией RETURN оператора ЯМД.<br />
В следующем примере код для функций GET_ROW_CNTS и UPDATE_ROW, кото-<br />
рые мы ранее реализовали с помощью средств пакета DBMS_SQL, переписан с исполь-<br />
зованием оператора EXECUTE IMMEDIATE. Начнем с функции GET_ROW_CNTS:</p>
<pre>EXECUTE IMMEDIATE 'оператор'
[INTO {переменная1., переменная2, . . . переменнаяN | запись}]
[USING [IN | ООТ | IN OUT] связываемая_переменная1, . . .
связываемая_переменнаяN]
[{RETURNING | RETURN} INTO результат1 [, . . . , р е з у л ь т а т N ] . . . ] ;</pre>
<pre>create or replace
function get_row_cnts(p_tname in varchar2) return number
as
l_cnt number;
begin
execute immediate
'select count(*) from ' || p_tname
into l_cnt;
return l_cnt;
end;
 /
Function created
set serveroutput on
exec dbms_output.put_line(get_row_cnts('emp'));
PL/SQL procedure successfully completed.</pre>
<p>Использовав оператор SELECT&#8230;INTO&#8230; в качестве аргумента для EXECUTE<br />
IMMEDIATE, мы существенно уменьшили объем кода. Девять процедурных шагов, не-<br />
обходимых при использовании пакета DBMS_SQL, превратились в один шаг в случае<br />
встроенного динамического SQL. Не всегда удается свести все к одному шагу — иногда<br />
необходимо три, как будет показано ниже, — но общая идея понятна. Встроенный ди-<br />
намический SQL в данном случае обеспечивает более высокую производительность при<br />
написании кода (последствия его использования с точки зрения производительности мы<br />
рассмотрим чуть позже). Также бросается в глаза отсутствие раздела EXCEPTION -<br />
обработка исключительных ситуаций не нужна, поскольку все происходит неявно. Нет<br />
курсора, который необходимо закрывать, ничего не нужно освобождать. Сервер Oracle<br />
все делает сам.</p>
<p>Теперь реализуем с помощью встроенного динамического SQL функцию UPDATE_ROW</p>
<pre>create or replace
 function update_row(p_owner in varchar2,
 p_newDname in varchar2,
 p_newLoc in varchar2,
 p_deptno in varchar2,
 p_rowid out varchar2)
 return number
 is
 begin
 execute immediate
 'update ' || p_owner || '.dept
 set dname = :bvl, loc = :bv2
 where deptno = to_number(:pk)
 returning rowid into <img src='http://osql.ru/wp-includes/images/smilies/icon_surprised.gif' alt=':o' class='wp-smiley' /> ut'
 using p_newDname, p_newLoc, p_deptno
 returning into p_rowid;return sql%rowcount;
 end;
 /
Function created.</pre>
<pre>set serveroutput on
declare
 l_rowid varchar(50);
 l_rows number;
 begin
 l_rows := update_row('SCOTT', 'CONSULTING',
 'WASHINGTON', '10', l_rowid);</pre>
<pre> dbms_output.put_line('Updated ' || l_rows || ' rows');
 dbms_output.put_line('its rowid was ' || l_rowid);
 end;
/
Updated 1 rows
its rowid was AAAGnuAAFAAAAESAAA
PL/SQL procedure successfully completed.</pre>
<p>Снова код существенно сократился — один шаг вместо шести; такой код проще чи-<br />
тать и сопровождать. В этих двух случаях встроенный динамический SQL, несомненно,<br />
превосходит средства пакета DBMS_SQL.<br />
Помимо оператора EXECUTE IMMEDIATE встроенный динамический SQL поддер-<br />
живает динамическую обработку курсорных переменных, REF CURSOR. Курсорные пе-<br />
ременные достаточно давно поддерживаются сервером Oracle (с версии 7.2). Первона-<br />
чально они позволяли открыть (OPEN) запрос (результирующее множество) в хранимой<br />
процедуре и передать ссылку на него клиенту. С их помощью хранимые процедуры<br />
возвращают результирующие множества клиентам при использовании VB, протоколов<br />
JDBC и ODBC или библиотеки OCI. Позднее, в версии 7.3, поддержка курсорных пере-<br />
менных была расширена, так что в PL/SQL появилась возможность использовать их не<br />
только в операторе OPEN, но и в операторе FETCH (в качестве клиента могла исполь-<br />
зоваться другая подпрограмма на PL/SQL). Это позволило подпрограмме на PL/SQL<br />
принимать результирующее множество в качестве входных данных и обрабатывать его.<br />
Таким образом, впервые стало возможно централизовать общую обработку результатов<br />
запросов: одна подпрограмма может выбирать данные из нескольких различных запро-<br />
сов (результирующих множеств). До появления версии Oracle 8i, однако, курсорные пе-<br />
ременные по сути были исключительно статические. На этапе компиляции (при созда-<br />
нии хранимой процедуры) надо было точно знать, какой SQL-запрос будет выполняться.<br />
Это было весьма существенное ограничение, поскольку не позволяло динамически из-<br />
менять условия запроса, запрашивать другую таблицу и т.п. Начиная с Oracle 8i встро-<br />
енный динамический SQL позволяет динамически открывать для запроса курсорную<br />
переменную. При этом используется следующий синтаксис:</p>
<pre>OPEN курсорная_переменная FOR 'select ...'
USING связываемая_переменная1, связываемая_переменная2, ...;</pre>
<p>Итак, с помощью курсорных переменных и динамического SQL можно реализовать<br />
обобщенную процедуру запроса таблицы в зависимости от входных данных и возвра-<br />
щения результирующего множества клиенту для дальнейшей обработки:</p>
<pre>create or replace package my_pkg
 as
 type refcursor_Type is ref cursor;</pre>
<pre> procedure get_emps(p_ename in varchar2 default NULL,
 p_deptno in varchar2 default NULL,
 p_cursor in out refcursor_type);
 end;
 /
Package created.
create or replace package body my_pkg
 as</pre>
<pre> procedure get_emps(p_ename in varchar2 default NULL,</pre>
<pre> p_deptno in varchar2 default NULL,</pre>
<pre> p_cursor in out refcursor_type)</pre>
<pre> is</pre>
<pre> l_query long;</pre>
<pre> l_bind varchar2(30);</pre>
<pre> begin</pre>
<pre> l_query := 'select deptno, ename, job from emp';</pre>
<pre> if (p_ename is not NULL)
 then
 l_query := l_query || ' where ename like <img src='http://osql.ru/wp-includes/images/smilies/icon_mad.gif' alt=':x' class='wp-smiley' /> ';
 l_bind := '%' || upper(p_ename) || '%';
 elsif (p_deptno is not NULL)
 then
 l_query := l_query || ' where deptno = to_number(:x)';
 l_bind := p_deptno;
 else
 raise_application_error(-20001,'Missing search criteria');
 end if;</pre>
<pre> open p_cursor for l_query using l_bind;
 end;
 end;
 /
Package body created.
variable С refcursor
set autoprint on
exec my_pkg.get_emps(p_ename =&gt; 'a', p_cursor =&gt; :C)
PL/SQL procedure successfully completed.

DEPTNO ENAME JOB
20 ADAMS CLERK
30 ALLEN SALESMAN
30 BLAKE MANAGER
10 CLARK MANAGER
30 JAMES CLERK
30 MARTIN SALESMAN
30 WARD SALESMAN
7 rows selected.
scott@TKYTE816&gt; exec my_pkg.get_emps(p_deptno=&gt; '10', p_cursor =&gt; :C)
PL/SQL procedure successfully completed.
DEPTNO ENAME JOB
10 CLARK MANAGER
10 KING PRESIDENT
10 MILLER CLERK</pre>
<p>Если созданный динамически запрос возвращает более одной строки, надо исполь-<br />
зовать представленный выше метод, а не оператор EXECUTE IMMEDIATE.<br />
Итак, по сравнению с представленными выше подпрограммами пакета DBMS_SQL,<br />
использование операторов EXECUTE IMMEDIATE и OPEN FOR существенно упро-<br />
щает написание программ. Значит ли это, что пакет DBMS_SQL больше использовать<br />
не придется? Определенно, — не значит. Представленные выше примеры показывают,<br />
насколько простым может быть использование динамического SQL, если количество свя-<br />
зываемых переменных известно во время компиляции. Если бы мы этого не знали, то<br />
не смогли бы использовать оператор EXECUTE IMMEDIATE так просто, как в пред-<br />
ставленных примерах. Для этого оператора количество связываемых переменных надо<br />
знать заранее. Пакет DBMS_SQL в этом отношении обеспечивает большую гибкость.<br />
Помимо количества связываемых переменных необходимо знать еще и столбцы, входя-<br />
щие в результат выполнения SQL-оператора SELECT. Если количество и типы этих<br />
столбцов неизвестны, использовать оператор EXECUTE IMMEDIATE тоже не удастся.<br />
Можно будет использовать оператор OPEN FOR, если клиент, получающий курсорную<br />
переменную, не является другой подпрограммой на языке PL/SQL.<br />
Оператор EXECUTE IMMEDIATE обеспечит более высокую производительность по<br />
сравнению с пакетом DBMS_SQL для всех операторов, анализируемых и выполняемых<br />
однократно (все наши примеры пока были именно такими). Для выполнения подпрог-<br />
рамм пакета DBMS_SQL в этом отношении требуется больше ресурсов, потому что<br />
нужно вызвать пять или шесть процедур там, где достаточно одного выполнения опера-<br />
тора EXECUTE IMMEDIATE.<br />
Однако пакет DBMS_SQL обеспечивает более высокую производительность, если<br />
его процедуры используются для многократного выполнения одного и того же проана-<br />
лизированного оператора. Оператор EXECUTE IMMEDIATE не позволяет &laquo;повторно<br />
использовать&raquo; проанализированные операторы. Он всегда разбирает оператор, и расхо-<br />
ды ресурсов на повторные выполнения этой операции со временем превышают расхо-<br />
ды на дополнительные вызовы процедур. Особое значение это приобретает в многополь-<br />
зовательской среде. Наконец, операторы EXECUTE IMMEDIATE и OPEN не позволя-<br />
ют обрабатывать массивы так же просто, как подпрограммы пакета DBMS_SQL и, как<br />
будет продемонстрировано, одно это может принципиально повлиять на производитель-<br />
ность.</p>
]]></content:encoded>
			<wfw:commentRss>http://osql.ru/?feed=rss2&amp;p=113</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Пакет DBMS_SQL</title>
		<link>http://osql.ru/?p=111</link>
		<comments>http://osql.ru/?p=111#comments</comments>
		<pubDate>Thu, 19 Nov 2009 22:35:33 +0000</pubDate>
		<dc:creator>admin</dc:creator>
				<category><![CDATA[Использование динамического SQL]]></category>

		<guid isPermaLink="false">http://osql.ru/?p=111</guid>
		<description><![CDATA[DBMS_SQL — это стандартный встроенный пакет, поставляемый вместе с серве-
ром. Стандартно он устанавливается в схеме пользователя SYS, а привилегия для его
выполнения предоставляется роли PUBLIC. Это означает, что не должно быть никаких
проблем с доступом к нему или созданием хранимых объектов, ссылающихся на его
процедуры, — никаких дополнительных или специальных привилегий для этого предо-
ставлять не надо. Одним из [...]]]></description>
			<content:encoded><![CDATA[<p>DBMS_SQL — это стандартный встроенный пакет, поставляемый вместе с серве-<br />
ром. Стандартно он устанавливается в схеме пользователя SYS, а привилегия для его<br />
выполнения предоставляется роли PUBLIC. Это означает, что не должно быть никаких<br />
проблем с доступом к нему или созданием хранимых объектов, ссылающихся на его<br />
процедуры, — никаких дополнительных или специальных привилегий для этого предо-<br />
ставлять не надо. Одним из положительных свойств пакета является доступность соот-<br />
ветствующей документации. Если при использовании DBMS_SQL необходимо вспом-<br />
нить ту или иную особенность, можно просто выполнить следующий сценарий:</p>
<pre>set pagesize 30</pre>
<pre>set pause on</pre>
<p>prompt He забудьте нажать ENTER, чтобы получить результа<br />
Не забудьте нажать ENTER, чтобы получить результат</p>
<pre>select text</pre>
<pre> from all_source</pre>
<pre> where name = 'DBMS_SQL'</pre>
<pre> and type = 'PACKAGE'</pre>
<pre>order by line</pre>
<pre>/</pre>
<pre>TEXT</pre>
<pre>package dbms_sql is</pre>
<pre>-- OVERVIEW</pre>
<pre>-- This package provides a means to use dynamic SQL to access the</pre>
<pre>database.</pre>
<pre>-- RULES AND LIMITATIONS</pre>
<p>Если необходимо узнать возможности или просмотреть примеры, используйте этот<br />
прием для всех стандартных пакетов DBMS_ или UTL_.<br />
Пакет DBMS_SQL реализует процедурный подход к использованию динамическо-<br />
го SQL. Этот подход сходен с тем, который используется в других языках (например,при программировании на Java с использованием JDBC или на С с использованием биб-<br />
лиотеки OCI) В общем случае, процесс, использующий пакет DBMS_SQL, будет иметь<br />
следующую структуру.<br />
• Вызов OPEN_CURSOR для получения дескриптора курсора.<br />
• Вызов PARSE для анализа оператора. Один и тот же дескриптор курсора можно<br />
использовать для обработки нескольких операторов. В каждый момент времени,<br />
однако, обрабатывается только один оператор.<br />
• Вызов BIND_VARIABLE или BIND_ARRAY для передачи входных данных опе-<br />
ратору.<br />
• Если обрабатывается запрос (оператор SELECT), необходимо вызвать процедуру<br />
DEFINE_COLUMN или DEFINE_ARRAY, чтобы указать серверу Oracle, как пе-<br />
редавать результаты (как массивы или как скалярные величины и какой тип дан-<br />
ных при этом использовать).<br />
• Вызов EXECUTE для выполнения оператора.<br />
• Если выполняется запрос, необходимо вызвать FETCH_ROWS для выборки дан-<br />
ных. Для получения данных по порядковому месту в списке выбора используется<br />
вызов COLUMN_VALUE.<br />
• Если же выполняется блок кода PL/SQL или оператор ЯМД с конструкцией<br />
RETURN, можно вызвать процедуру VARIABLE_VALUE для получения резуль-<br />
татов (параметров типа OUT) из блока по имени.<br />
• Вызов CLOSE_CURSOR.<br />
В следующем псевдокоде продемонстрирована последовательность шагов для дина-<br />
мического выполнения запроса:<br />
1) Открыть курсор<br />
2) Проанализировать оператор<br />
3) При необходимости получить описание оператора, чтобы выяснить<br />
количество и типы возвращаемых столбцов<br />
4) Выполнить цикл по i no связываемым переменным (входным)<br />
Связать i-ую входную переменную с оператором<br />
5) Выполнить цикл по i по возвращаемым столбцам<br />
Определить i-ый столбец, сообщив серверу Oracle тип переменной, в<br />
которую будут выбираться данные<br />
6) Выполнить оператор<br />
7) Выполнять цикл пока удается выбрать строку<br />
 <img src='http://osql.ru/wp-includes/images/smilies/icon_cool.gif' alt='8)' class='wp-smiley' /> Выполнить цикл по i по возвращаемым столбцам<br />
Получить значение i-го столбца строки с помощью column_value<br />
Конец цикла по строкам<br />
9) Закрыть курсор<br />
Для выполнения PL/SQL-блока или оператора ЯМД используется следующий псев-<br />
докод:<br />
1) Открыть курсор<br />
2) Проанализировать оператор<br />
3) Выполнить цикл по i по связываемым переменным (входным и выходным)Связать i-ую переменную с оператором<br />
4) Выполнить оператор<br />
5) Выполнить цикл по i по выходным связываемым переменным<br />
Получить значение i-й выходной переменной с помощью variable_value<br />
6) Закрыть курсор</p>
<p>Наконец, при выполнении операторов ЯОД (в которых нельзя использовать связы-<br />
ваемые переменные), PL/SQL-блоков или операторов ЯМД, в которых нет связывае-<br />
мых переменных, представленный выше алгоритм упрощается (хотя, для этого типа опе-<br />
раторов я всегда предпочитаю использовать не пакет DBMS_SQL, а встроенный<br />
динамический SQL):</p>
<p>1) Открыть курсор<br />
2) Проанализировать оператор<br />
3) Выполнить оператор<br />
4) Закрыть курсор<br />
Рассмотрим пример использования пакета DBMS_SQL для выполнения запроса, под-<br />
считывающего количество строк в таблице базы данных, к которой пользователь имеет<br />
доступ:</p>
<pre>create or replace
 function get_row_cnts(p_tname in varchar2) return number</pre>
<pre> as
l_theCursor integer;
l_columnValue number default NULL;
 l_status integer;
begin

-- Шаг 1, открыть курсор.
 theCursor := dbms_sql.open_cursor;</pre>
<p>Мы начинаем блок с обработчиком исключительных ситуаций. Если по ходу работы<br />
этого блока возникает ошибка, необходимо закрыть только что открытый курсор в об-<br />
работчике исключительных ситуаций, чтобы предотвратить &laquo;утечку курсоров&raquo;, когда дес-<br />
криптор курсора теряется при распространении исключительной ситуации за пределы<br />
функции.<br />
begin</p>
<pre> -- Шаг 2, проанализировать запрос.</pre>
<pre>dbms_sql.parse(c =&gt; l_theCursor,</pre>
<pre> statement =&gt; 'select count(*) from ' ||</pre>
<pre>-&gt;p_tname,</pre>
<pre> language_flag =&gt; dbms_sql.native);</pre>
<p>Обратите внимание, что параметр language_flag получает значение одной из констант<br />
пакета DBMS_SQL.NATIVE. Это вызывает анализ запроса по правилам сервера, вы-<br />
полняющего код. Можно также задать значения DBMS_SQL.V6 или DBMS_SQL.V7.<br />
Я всегда использую значение NATIVE.</p>
<p>Шаги 3 и 4 из представленного ранее псевдокода нам не нужны, поскольку резуль-<br />
таты известны и никаких связываемых переменных в этом примере нет.</p>
<p>&#8211; Шаг 5, убедиться, что запрос возвращает данные типа NUMBER.</p>
<pre> dbms_sql.define_column (с =&gt; l_theCursor,</pre>
<pre> position =&gt; 1,</pre>
<pre> column =&gt; l_columnValue);</pre>
<p>Процедура DEFINE_COLUMN — перегруженная, так что компилятор сам опреде-<br />
ляет, когда надо вызывать версию для типа NUMBER, а когда — для DATE или<br />
VARCHAR.</p>
<pre> -- Шаг 6, выполнить оператор.</pre>
<pre> l_status := dbms_sql.execute(l_theCursor);</pre>
<p>Если бы выполнялся оператор ЯМД, переменная L_STATUS получила бы значение,<br />
равное количеству возвращенных строк. Для оператора SELECT возвращаемое значе-<br />
ние несущественно.</p>
<pre>-- Шаг 7, выбрать строки.</pre>
<pre> if (dbms_sql.fetch_rows(c =&gt; l_theCursor) &gt; 0)</pre>
<pre> then</pre>
<pre>-- Шаг 8, получить значения из очередной строки.</pre>
<pre>dbms_sql.column_value(c =&gt; l_theCursor,</pre>
<pre>position =&gt; 1,</pre>
<pre>value =&gt; l_columnValue);</pre>
<pre> end if;</pre>
<pre>
-- Шаг 9, закрыть курсор.</pre>
<pre>dbms_sql.close_cursor(c =&gt; l_theCursor);</pre>
<pre>return l_columnValue;</pre>
<pre>exception</pre>
<pre>when others then</pre>
<pre>dbms_output.put_line (' = = &gt; ' || sqlerrm);</pre>
<pre>dbms_sql.close_cursor(с =&gt; l_theCursor);</pre>
<pre>RAISE;</pre>
<pre>end;</pre>
<pre>end;
/
Function created.
set serveroutput on
 begin
dbms_output.put_line('Emp has this many rows ' ||
get_row_cnts('emp'));</pre>
<pre> end;</pre>
<pre>/</pre>
<pre>Emp has this many rows 14</pre>
<pre>PL/SQL procedure successfully completed.</pre>
<pre> begin</pre>
<pre>dbms_output.put_line('Not a table has this many rows ' ||get_row_cnts('NOT_A_TABLE');</pre>
<pre>end;</pre>
<pre>/</pre>
<pre>ORA-00942: table or view does not exist</pre>
<pre>begin</pre>
<pre>ERROR at line 1:</pre>
<pre>ORA-00942: table or view does not exist</pre>
<pre>ORA-06512: at "SCOTT.GET_ROW_CNTS", line 60</pre>
<pre>ORA-06512: at line 2</pre>
<p>Рассмотренный пример начинается созданием курсора с помощью вызова<br />
DBMS_SQL.OPEN_CURSOR. Следует отметить, что это специфический курсор<br />
DBMS_SQL — его нельзя передать для выборки данных в приложение на Visual Basic<br />
или использовать в качестве PL/SQL-курсора. Для выборки данных с помощью этого<br />
курсора необходимо использовать подпрограммы пакета DBMS_SQL. Затем мы про-<br />
анализировали запрос SELECT COUNT(*) FROM TABLE, где значение TABLE пере-<br />
дается при вызове во время выполнения — оно просто конкатенируется со строкой зап-<br />
роса. Приходится &laquo;вклеивать&raquo; имя таблицы в запрос, поскольку связываемые переменные<br />
нельзя использовать в качестве идентификатора (имени таблицы или имени столб-<br />
ца, например). После анализа запроса мы вызвали DBMS_SQL.DEFINE_COLUMN,<br />
чтобы указать, что первый (и единственный в данном случае) столбец в списке<br />
SELECT должен интерпретироваться при выборке как тип NUMBER. To, что мы<br />
хотим выбирать данные именно этого типа, явно не указано — процедура<br />
DBMS_SQL.DEFINE_COLUMN перегружена и имеет несколько версий для данных<br />
типа VARCHAR, NUMBER, DATE, BLOB, CLOB и так далее. Тип возвращаемого зна-<br />
чения определяется по типу переменной, в которую он помещается. Поскольку пере-<br />
менная L_COLUMNVALUE в рассмотренном примере имеет тип NUMBER, вызыва-<br />
ется версия процедуры DEFINE_COLUMN для чисел. Затем мы вызываем<br />
DBMS_SQL.EXECUTE. Если бы выполнялся оператор INSERT, UPDATE или DELETE,<br />
функция EXECUTE вернула бы количество затронутых строк. В случае запроса возвра-<br />
щаемое значение функции не определено, и его можно проигнорировать. После выпол-<br />
нения оператора вызывается функция DBMS_SQL.FETCH_ROWS. Функция<br />
FETCH_ROWS возвращает количество фактически выбранных строк. В нашем случае,<br />
поскольку связывались скалярные переменные (не массивы), функция FETCH_ROWS<br />
будет возвращать 1 до тех пор, пока не исчерпаются данные, — тогда она вернет 0. При<br />
извлечении каждой строки мы вызываем DBMS_SQL.COLUMN_VALUE для каждого<br />
столбца в списке выбора, чтобы получить его значение. Наконец, мы завершаем выпол-<br />
нение функции, закрывая курсор с помощью вызова DBMS_SQL.CLOSE_CURSOR.<br />
Теперь рассмотрим, как использовать пакет DBMS_SQL для обработки динамичес-<br />
ки формируемых параметризованных PL/SQL-блоков или операторов ЯМД. Я часто ис-<br />
пользую такое динамическое формирование, например, при загрузке данных из файлов<br />
операционной системы с помощью пакета UTL_FILE (он позволяет читать текстовые<br />
файлы в PL/SQL). Пример подобного рода утилиты был представлен в главе 9. Там мы<br />
использовали пакет DBMS_SQL для динамического построения операторов INSERT,<br />
в которых количество столбцов становится известным только при выполнении и меня-</p>
<pre>get_row_cnts('NOT_A_TABLE')&gt;;</pre>
<pre>end;</pre>
<pre> /
==&gt; ORA-00942: table or view does not exist
begin
ERROR at line 1:
ORA-00942: table or view does not exist
ORA-06512: at "SCOTT.GET_ROW_CNTS", line 60
ORA-06512: at line 2</pre>
<p>Рассмотренный пример начинается созданием курсора с помощью вызова<br />
DBMS_SQL.OPEN_CURSOR. Следует отметить, что это специфический курсор<br />
DBMS_SQL — его нельзя передать для выборки данных в приложение на Visual Basic<br />
или использовать в качестве PL/SQL-курсора. Для выборки данных с помощью этого<br />
курсора необходимо использовать подпрограммы пакета DBMS_SQL. Затем мы про-<br />
анализировали запрос SELECT COUNT(*) FROM TABLE, где значение TABLE пере-<br />
дается при вызове во время выполнения — оно просто конкатенируется со строкой зап-<br />
роса. Приходится &laquo;вклеивать&raquo; имя таблицы в запрос, поскольку связываемые переменные<br />
нельзя использовать в качестве идентификатора (имени таблицы или имени столб-<br />
ца, например). После анализа запроса мы вызвали DBMS_SQL.DEFINE_COLUMN,<br />
чтобы указать, что первый (и единственный в данном случае) столбец в списке<br />
SELECT должен интерпретироваться при выборке как тип NUMBER. To, что мы<br />
хотим выбирать данные именно этого типа, явно не указано — процедура<br />
DBMS_SQL.DEFINE_COLUMN перегружена и имеет несколько версий для данных<br />
типа VARCHAR, NUMBER, DATE, BLOB, CLOB и так далее. Тип возвращаемого зна-<br />
чения определяется по типу переменной, в которую он помещается. Поскольку пере-<br />
менная L_COLUMNVALUE в рассмотренном примере имеет тип NUMBER, вызыва-<br />
ется версия процедуры DEFINE_COLUMN для чисел. Затем мы вызываем<br />
DBMS_SQL.EXECUTE. Если бы выполнялся оператор INSERT, UPDATE или DELETE,<br />
функция EXECUTE вернула бы количество затронутых строк. В случае запроса возвра-<br />
щаемое значение функции не определено, и его можно проигнорировать. После выпол-<br />
нения оператора вызывается функция DBMS_SQL.FETCH_ROWS. Функция<br />
FETCH_ROWS возвращает количество фактически выбранных строк. В нашем случае,<br />
поскольку связывались скалярные переменные (не массивы), функция FETCH_ROWS<br />
будет возвращать 1 до тех пор, пока не исчерпаются данные, — тогда она вернет 0. При<br />
извлечении каждой строки мы вызываем DBMS_SQL.COLUMN_VALUE для каждого<br />
столбца в списке выбора, чтобы получить его значение. Наконец, мы завершаем выпол-<br />
нение функции, закрывая курсор с помощью вызова DBMS_SQL.CLOSE_CURSOR.<br />
Теперь рассмотрим, как использовать пакет DBMS_SQL для обработки динамичес-<br />
ки формируемых параметризованных PL/SQL-блоков или операторов ЯМД. Я часто ис-<br />
пользую такое динамическое формирование, например, при загрузке данных из файлов<br />
операционной системы с помощью пакета UTL_FILE (он позволяет читать текстовые<br />
файлы в PL/SQL). Пример подобного рода утилиты был представлен в главе 9. Там мы<br />
использовали пакет DBMS_SQL для динамического построения операторов INSERT,<br />
в которых количество столбцов становится известным только при выполнении и меня-ется от вызова к вызову. Нельзя использовать встроенный динамический SQL для заг-<br />
рузки в таблицу произвольного количества столбцов, поскольку для этого уже на этапе<br />
компиляции необходимо точно знать количество связываемых переменных. Следующий<br />
пример создан специально, чтобы показать особенности использования подпрограмм па-<br />
кета DBMS_SQL при работе с блоками PL/SQL и операторами ЯМД (это пример про-<br />
ще реализовать с помощью встроенного динамического SQL, поскольку в этом случае<br />
количество связываемых переменных известно во время компиляции):</p>
<pre>create or replace</pre>
<pre>function update_row(p_owner in varchar2,</pre>
<pre> p_newDname in varchar2,</pre>
<pre>p_newLoc in varchar2,</pre>
<pre> p_deptno in varchar2,</pre>
<pre> p_rowid out varchar2)</pre>
<pre> return number</pre>
<pre> is</pre>
<pre> l_theCursor integer;</pre>
<pre> l_columnValue number default NULL;</pre>
<pre>l_status integer;</pre>
<pre>l_update long;</pre>
<pre>begin</pre>
<pre> l_update := 'update ' || p_owner || '.dept</pre>
<pre>set dname = :bvl, loc - :bv2</pre>
<pre>where deptno = to_number(:pk)</pre>
<pre>returning rowid into <img src='http://osql.ru/wp-includes/images/smilies/icon_surprised.gif' alt=':o' class='wp-smiley' /> ut';</pre>
<pre>
-- Шаг 1, открыть курсор.</pre>
<pre> l_theCursor := dbms_sql.open_cursor;</pre>
<p>Начнем вложенный блок с обработчиком исключительных ситуаций. Если в этом<br />
блоке кода возникнет ошибка, необходимо обработать ее как можно ближе к месту воз-<br />
никновения и закрыть курсор, чтобы избежать &laquo;утечки курсоров&raquo;, когда дескриптор<br />
открытого курсора просто теряется при распространении ошибки за пределы подпрог-<br />
раммы.</p>
<pre> begin</pre>
<pre>-- Шаг 2, проанализировать запрос.</pre>
<pre>dbms_sql.parse(c =&gt; l_theCursor,</pre>
<pre>statement =&gt; l_update,</pre>
<pre>language_flag =&gt; dbms_sql.native);</pre>
<pre>
-- Шаг 3, связать все входные и выходные переменные.</pre>
<pre>dbms_sql.bind_variable(c =&gt; l_theCursor,</pre>
<pre> name =&gt; ':bv1',</pre>
<pre>value =&gt; p_newDname);</pre>
<pre> dbms_sql.bind_variable(c =&gt; l_theCursor,</pre>
<pre> name =&gt; ':bv2',</pre>
<pre>value =&gt; p_newLoc);</pre>
<pre>dbms_sql.bind_variable(c =&gt; l_theCursor,</pre>
<pre>name =&gt; ':pk',</pre>
<pre>value =&gt; p_deptno);</pre>
<pre> dbms_sql.bind_variable(c =&gt; l_theCursor,</pre>
<pre> name =&gt; ':out',</pre>
<pre>value =&gt; p_rowid,</pre>
<pre>out_value_size =&gt; 4000);</pre>
<p>Учтите, что, хотя возвращаемые переменные передаются как параметры в режиме<br />
OUT, необходимо связать их перед выполнением. Необходимо также указать наиболь-<br />
ший размер ожидаемого результата (OUT_VALUE_SIZE), чтобы сервер Oracle выделил<br />
под него соответствующее пространство.</p>
<pre>-- Шаг 4: выполнить оператор. Поскольку это оператор ЯМД,</pre>
<pre>-- в переменной L_STATUS окажется количество измененных строк.</pre>
<pre>-- Именно это значение мы и возвращаем.</pre>
<pre>
 l_status := dbms_sql.execute(l_theCursor);</pre>
<pre>
-- Шаг 5: выбрать OUT-переменные из результатов выполнения.</pre>
<pre> dbms_sql.variable_value(c =&gt; l_theCursor,</pre>
<pre> name =&gt; ':out',</pre>
<pre>value =&gt; p_rowid);</pre>
<pre>
-- Шаг 6: закрыть курсор.</pre>
<pre> dbms_sql.close_cursor(с =&gt; l_theCursor);</pre>
<pre>return l_columnValue;</pre>
<pre> exception</pre>
<pre> when dup_val_on_index then</pre>
<pre>dbms_output.put_line('==&gt; ' || sqlerrm);</pre>
<pre>dbms_sql.close_cursor(с =&gt; l_theCursor);</pre>
<pre>RAISE;</pre>
<pre>end;</pre>
<pre>end;</pre>
<pre> /</pre>
<pre>Function created.</pre>
<pre>set serveroutput on</pre>
<pre>declare</pre>
<pre> l_rowid varchar(50);</pre>
<pre> l_rows number;</pre>
<pre>begin</pre>
<pre> l_rows := update_row('SCOTT', 'CONSULTING', 'WASHINGTON',</pre>
<pre>'10', l_rowid);</pre>
<pre>
 dbms_output.put_line('Updated ' || l_rows || ' rows');</pre>
<pre> dbms_output.put_line('its rowid was ' || l_rowid);end;</pre>
<pre> /</pre>
<pre>Updated 1 rows</pre>
<pre>its rowid was AAAGnuAAFAAAAESAAA</pre>
<pre>PL/SQL procedure successfully completed.</pre>
<p>Итак, я продемонстрировал особенности использования пакета DBMS_SQL для вы-<br />
полнения блока кода с передачей входных данных и выборкой результатов. Повторю<br />
еще раз: представленный выше блок кода лучше реализовать с помощью встроенного<br />
динамического SQL (чуть ниже мы так и сделаем). Подпрограммы пакета DBMS_SQL<br />
в нем применялись в основном для демонстрации использования соответствующего фун-<br />
кционального интерфейса. В других главах книги, в частности в главе 9, посвященной<br />
загрузке данных, продемонстрировано, почему пакет DBMS_SQL по-прежнему ши-<br />
роко используется. В главе 9 рассмотрен код программ загрузки и выгрузки данных<br />
на PL/SQL. В них средства DBMS_SQL используются в полном объеме, позволяя об-<br />
рабатывать неизвестное количество столбцов любого типа как во входных данных (для<br />
операторов INSERT), так и в результатах (для операторов SELECT).<br />
Мы рассмотрели примерно 75 процентов функциональных возможностей пакета<br />
DBMS_SQL. Чуть позже, многократно выполняя один и тот же динамически сформи-<br />
рованный оператор, мы рассмотрим взаимодействие с помощью массивов и сравним ис-<br />
пользование пакета DBMS_SQL и встроенного динамического SQL. Пока, однако, мы<br />
завершим обзор пакета DBMS_SQL. Полный список входящих в него подпрограмм и<br />
описание их входных/выходных параметров можно найти в руководстве Oracle8i Supplied<br />
PL/SQL Packages Reference, где отдельно рассмотрена каждая подпрограмма.</p>
]]></content:encoded>
			<wfw:commentRss>http://osql.ru/?feed=rss2&amp;p=111</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Когда использовать динамический SQL?</title>
		<link>http://osql.ru/?p=109</link>
		<comments>http://osql.ru/?p=109#comments</comments>
		<pubDate>Thu, 19 Nov 2009 22:09:02 +0000</pubDate>
		<dc:creator>admin</dc:creator>
				<category><![CDATA[Когда использовать динамический SQL?]]></category>

		<guid isPermaLink="false">http://osql.ru/?p=109</guid>
		<description><![CDATA[Многие задачи требуют использования динамического SQL в PL/SQL. Вот лишь не-
которые из них.
• Разработка обобщенных процедур, выполняющих стандартные действия вроде
выгрузки данных в файлы.
• Разработка универсальных процедур загрузки данных в не известные заранее таб-
лицы.
• Динамический вызов других PL/SQL-процедур во время выполнения.
• Генерация условий (например, конструкции WHERE) в процессе работы на ос-
нове введенных пользователем данных. Это, пожалуй, [...]]]></description>
			<content:encoded><![CDATA[<p>Многие задачи требуют использования динамического SQL в PL/SQL. Вот лишь не-<br />
которые из них.</p>
<p>• Разработка обобщенных процедур, выполняющих стандартные действия вроде<br />
выгрузки данных в файлы.<br />
• Разработка универсальных процедур загрузки данных в не известные заранее таб-<br />
лицы.<br />
• Динамический вызов других PL/SQL-процедур во время выполнения.<br />
• Генерация условий (например, конструкции WHERE) в процессе работы на ос-<br />
нове введенных пользователем данных. Это, пожалуй, основная причина исполь-<br />
зования динамического SQL большинством разработчиков.<br />
• Выполнение операторов ЯОД. Поскольку PL/SQL не разрешает включать стати-<br />
ческие операторы ЯОД в код приложения, остается использовать динамический<br />
SQL. Это позволит выполнять операторы, начинающиеся с ключевых слов<br />
CREATE, ALTER, GRANT, DROP и т.п.</p>
<p>Решаться перечисленные задачи будут с помощью двух средств языка PL/SQL.<br />
Сначала мы рассмотрим использование стандартного пакета DBMS_SQL. Этот па-<br />
кет существует уже достаточно давно, он появился в версии 7.1. Пакет обеспечивает<br />
процедурный метод выполнения динамического SQL, аналогичный использованию<br />
функциональных интерфейсов (таких как JDBC или ODBC). Затем поговорим о<br />
встроенном динамическим SQL (который реализуется в PL/SQL оператором EXECUTE<br />
IMMEDIATE). Это декларативный способ выполнения динамического SQL в языке PL/<br />
SQL и в большинстве случаев он синтаксически намного проще, чем использование<br />
пакета DBMS_SQL; кроме того, он обеспечивает более высокую производительность.<br />
Учтите, что многие подпрограммы пакета DBMS_SQL по-прежнему являются жиз-<br />
ненно важными и активно используются в PL/SQL. Мы сравним два метода и попыта-<br />
емся четко сформулировать, когда имеет смысл использовать каждый из них. Как толь-<br />
ко стало понятно, что необходимо использовать динамический SQL (статический SQL —<br />
лучший выбор в большинстве случаев), придется выбирать реализацию на основе паке-<br />
та DBMS_SQL или встроенного динамического SQL.<br />
Пакет DBMS_SQL необходимо использовать в следующих случаях.</p>
<p>• Если заранее не известно количество или типы столбцов, с которыми придется<br />
работать. Пакет DBMS_SQL включает процедуры для описания результирующе-<br />
го множества. Встроенный динамический SQL не позволяет получить такое опи-<br />
сание. При использовании встроенного динамического SQL необходимо знать ха-<br />
рактеристики результирующего множества при компиляции, если результаты<br />
необходимо обрабатывать в PL/SQL.<br />
• Если заранее не известно количество или типы связываемых переменных, с ко-<br />
торыми придется работать. Пакет DBMS_SQL по ходу выполнения позволяет<br />
привязать с помощью процедур входные переменные к операторам. Встроенный<br />
динамический SQL требует учета количества и типов связываемых переменных<br />
на этапе компиляции.<br />
• Когда необходимо выбирать или вставлять тысячи строк и можно использовать<br />
обработку массивов. Пакет DBMS_SQL поддерживает обработку массивов — воз-<br />
можность выбрать N строк за раз, одним вызовом. Встроенный динамический SQL<br />
обычно не позволяет этого сделать, но это ограничение можно обойти, как будет<br />
показано далее.<br />
• Если в сеансе многократно выполняется один и тот же оператор. Пакет<br />
DBMS_SQL позволяет один раз разобрать оператор, а затем выполнять его мно-<br />
гократно. При использовании встроенного динамического SQL мягкий разбор<br />
будет осуществляться при каждом выполнении. Дополнительные повторные разборы нежелательны.</p>
<p>Встроенный динамический SQL имеет смысл использовать в следующих случаях.</p>
<p>• Когда количество и типы столбцов, с которыми придется работать, заранее изве-<br />
стны.<br />
• Когда заранее известно количество и типы связываемых переменных. (Можно так-<br />
же использовать контексты приложений, чтобы с помощью более простого встро-<br />
енного динамического SQL выполнять операторы с заранее неизвестным коли-<br />
чеством или типами связываемых переменных.)<br />
• Когда необходимо выполнять операторы ЯОД.<br />
• Если динамически формируемые операторы будут выполняться лишь несколько<br />
раз (оптимальный вариант — однократно).</p>
]]></content:encoded>
			<wfw:commentRss>http://osql.ru/?feed=rss2&amp;p=109</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Сравнение динамического и статического SQL</title>
		<link>http://osql.ru/?p=103</link>
		<comments>http://osql.ru/?p=103#comments</comments>
		<pubDate>Wed, 18 Nov 2009 22:48:43 +0000</pubDate>
		<dc:creator>admin</dc:creator>
				<category><![CDATA[Сравнение динамического и статического SQL]]></category>

		<guid isPermaLink="false">http://osql.ru/?p=103</guid>
		<description><![CDATA[Использование динамического SQL — естественная возможность работать с базой
данных через функциональный интерфейс, такой как ODBC, JDBC и OCI. Статичес-
кий SQL обычно принято использовать в средах с предварительной компиляцией кода,
таких как Pro*C, SQLJ и PL/SQL (я не оговорился: компилятор PL/SQL можно рассмат-
ривать как прекомпилятор). При работе через функциональный интерфейс поддержи-
вается только динамический SQL. Программист создает запрос [...]]]></description>
			<content:encoded><![CDATA[<p>Использование динамического SQL — естественная возможность работать с базой<br />
данных через функциональный интерфейс, такой как ODBC, JDBC и OCI. Статичес-<br />
кий SQL обычно принято использовать в средах с предварительной компиляцией кода,<br />
таких как Pro*C, SQLJ и PL/SQL (я не оговорился: компилятор PL/SQL можно рассмат-<br />
ривать как прекомпилятор). При работе через функциональный интерфейс поддержи-<br />
вается только динамический SQL. Программист создает запрос в виде строки, а затем<br />
эта строка анализируется, связываются входящие в нее переменные, запрос выполняет-<br />
ся, при необходимости выбираются строки из результирующего множества через кур-<br />
сор и, наконец, соответствующий курсор закрывается. В среде статического SQL эти<br />
действия выполняются автоматически. Для сравнения создадим две выполняющие оди-<br />
наковые действия PL/SQL-процедуры: одну с — использованием динамического SQL, а<br />
вторую — с использованием статического. Вот версия на основе динамического SQL:</p>
<pre>create or replace procedure DynEmpProc(p_job in varchar2)
as
type refcursor is ref cursor;</pre>
<pre> -- При использовании динамического SQL необходимо
 -- создать хост-переменные и выделить ресурсы.
 l_cursor refcursor;
 l_ename emp.ename%type;
 begin</pre>
<pre> -- Начинаем с анализа запроса
 open l_cursor for
 'select ename
 from emp
 where job = <img src='http://osql.ru/wp-includes/images/smilies/icon_mad.gif' alt=':x' class='wp-smiley' /> ' USING in p_job;
 loop
 -- и явно ВЫБИРАЕМ данные через курсор.
 fetch l_cursor into l_ename;</pre>
<pre> -- Необходимо самостоятельно обрабатывать ошибки
-- и делать выборку
 exit when l_cursor%notfound;
 dbms_output.put_line(l_ename);
 end loop;</pre>
<pre> -- He забываем освободить ресурсы
 close l_cursor;
 exception
 when others then
 -- а также перехватить и обработать все ошибки,
 -- чтобы не допустить утечки ресурсов
 -- при возникновении ошибок.
 if (l_cursor%isopen)
 then
 close l_cursor;
 end if;
 RAISE;
 end;
 /
Procedure created.</pre>
<p>А вот что мы имеем в случае статического SQL:</p>
<pre>create or replace procedure StaticEmpProc(p_job in varchar2)
as
begin
 for x in (select ename from emp where job = p_job)
 loop
 dbms_output.put_line(x.ename);
 end loop;
 end;
  /
Procedure created.</pre>
<p>Эти две процедуры делают то же самое:</p>
<pre>set serveroutput on size 1000000
exec DynEmpProc('CLERK')
SMITH
ADAMS
JAMES
MILLER
PL/SQL procedure successfully completed.</pre>
<pre>exec StaticEmpProc('CLERK')
SMITH
ADAMS
JAMBS
MILLER
PL/SQL procedure successfully completed.</pre>
<p>Понятно, однако, что версия с динамическим SQL требует от разработчика написа-<br />
ния гораздо большего объема кода. По опыту знаю: статический SQL обеспечивает бо-<br />
лее высокую производительность труда программиста при написании кода (приложения<br />
разрабатываются быстрее), но динамический SQL обеспечивает большую гибкость при<br />
выполнении (программа в ходе работы может делать то, что не внесено в ее код явно).<br />
Кроме того, статический SQL (особенно в среде PL/SQL) будет выполняться намного<br />
эффективнее, чем динамический. Используя статический SQL, PL/SQL-машина при<br />
обработке одной строки интерпретируемого кода может сделать то, на что потребуется<br />
пять или шесть строк интерпретируемого кода с динамическим SQL. Поэтому я исполь-<br />
зую статический SQL где только возможно и применяю динамический, только если по-<br />
другому задачу решить нельзя. Оба они эффективны, ни один не имеет принципиаль-<br />
ных преимуществ перед другим, и оба имеют свои специфические возможности и<br />
средства повышения производительности.</p>
]]></content:encoded>
			<wfw:commentRss>http://osql.ru/?feed=rss2&amp;p=103</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Динамический SQL</title>
		<link>http://osql.ru/?p=100</link>
		<comments>http://osql.ru/?p=100#comments</comments>
		<pubDate>Wed, 18 Nov 2009 22:34:33 +0000</pubDate>
		<dc:creator>admin</dc:creator>
				<category><![CDATA[Динамический SQL]]></category>

		<guid isPermaLink="false">http://osql.ru/?p=100</guid>
		<description><![CDATA[Обычно при разработке программ все используемые в них SQL-операторы явно за-
писываются в исходном коде. Такой вариант использования SQL-операторов обычно на-
зывают статический SQL. Многие полезные программы, однако, до момента запуска не
&#171;знают&#187;, какие именно SQL-операторы будут выполняться. Именно так и появляется ди-
намический SQL — программа при запуске выполняет SQL-операторы, неизвестные во
время компиляции. Возможно, программа генерирует запросы по [...]]]></description>
			<content:encoded><![CDATA[<p>Обычно при разработке программ все используемые в них SQL-операторы явно за-<br />
писываются в исходном коде. Такой вариант использования SQL-операторов обычно на-<br />
зывают статический SQL. Многие полезные программы, однако, до момента запуска не<br />
&laquo;знают&raquo;, какие именно SQL-операторы будут выполняться. Именно так и появляется ди-<br />
намический SQL — программа при запуске выполняет SQL-операторы, неизвестные во<br />
время компиляции. Возможно, программа генерирует запросы по ходу работы на осно-<br />
ве введенных пользователем условий; возможно, это специализированная программа заг-<br />
рузки данных. Утилита SQL*Plus — прекрасный пример такого рода программы, как и<br />
любое другое средство выполнения произвольных запросов или генерации отчетов. Ути-<br />
лита SQL*Plus позволяет выполнить любой SQL-оператор и показать результаты его вы-<br />
полнения* хотя при ее компиляции операторы, которые выполняет пользователь, опре-<br />
деленно не были известны.<br />
В этом разделе мы обсудим, когда возникает необходимость использовать динамичес-<br />
кий SQL в программах и когда его имеет смысл применять. Мы сосредоточимся на ис-<br />
пользовании динамического SQL в программах на языке PL/SQL, поскольку именно в<br />
этой среде большинство разработчиков и используют динамический SQL в предвари-<br />
тельно компилируемом формате. Поскольку использование динамического SQL — един-<br />
ственный способ выполнить SQL-операторы в программах на языке Java через интер-<br />
фейс JDBC (выполнить динамический SQL в среде прекомпилятора SQLJ можно только<br />
через интерфейс JDBC) и на языке С при использовании библиотеки OCI, не имеет<br />
смысла обсуждать эти среды в данном контексте. В этих средах есть только динамичес-<br />
кий SQL; статический SQL вообще не поддерживается, так что там просто нет выбора.<br />
Встроенный динамический SQL появился в Oracle 8.1.5<br />
и является одной из важнейших возможностей всех последующих версий.</p>
]]></content:encoded>
			<wfw:commentRss>http://osql.ru/?feed=rss2&amp;p=100</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
	</channel>
</rss>
