Программирование >>  Oracle 

1 ... 220 221 222 [ 223 ] 224 225 226 ... 469


1076

Глава 12

21 then

22 execute Immediate p max cols query into l max cols;

23 else

24 raise application error(-20001, He могу определить

максимальное количество столбцов) ;

25 end if;

26 27

2 8 -- Теперь создаем запрос, который позволяет ответит на

-- поставленный вопрос. . 29 -- Начинаем со столбцов Cl, C2, ... СХ:

31 l query := select ;

32 for i in 1 .. p anchor.count

34 loop

35 l query := l query И p anchor(i) И ,;

36 end loop;

38 -- Теперь добавляем транспонируемые столбцы С{х+1}... CN:

39 -- Формат: max(decode(rn,l,C{X+l},null)) сх+1 1

41 for i in 1 .. l max cols

42 loop

43 for j in 1 .. p pivot.count

44 loop

45 l query := l query

46 max(decode(rn,Hill,M

47 p pivot(j)M,null)) М

48 p pivot(j) М М i М ,;

49 end loop;

50 end loop;

52 -- Теперь просто добавляем исходный запрос 53

54 l query := rtrim(l query ) from ( p query ) group by ;

56 -- а затем - столбцы, по которым надо группировать...

58 for i in 1 .. p anchor.count

59 loop

60 l query := l query p anchor(i) ,;

61 end loop;

62 l query := rtrim(l query ); 63

64 -- и возвращаем курсор для результирующего множества

66 execute immediate alter session set cursor sharing=force;

67 open p cursor for l query;

68 execute immediate alter session set cursor sharing=exact;

69 end;



Аналитические функции 77

71 end;

72 /

Package body created.

Понадобилось несколько строковых функций для перезаписи запроса и динамическое открытие курсорной переменной (REF CURSOR). Поскольку вполне вероятно, что в условии запроса есть константы, мы включаем опцию cursor sharing перед анализом запроса, чтобы принудительно использовались связываемые переменные, а затем отключаем ее. (Подробнее об этом см. в главе 10, посвященной настройке производительности). В результате получаем полностью проанализированный запрос, готовый для извлечения данных через курсорную переменную.

Доступ к строкам вокруг текущей строки

Часто необходимо обращаться к данным не только в текущей строке, но и в ближайших предыдущих или последующих. Предположим, необходимо создать отчет, в котором по отделам были бы представлены все сотрудники, причем, для каждого сотрудника выдана дата его приема на работу, за сколько дней до этой даты последний раз принимали сотрудника на работу, и через сколько дней после этого приняли на работу следующего сотрудника. Написание подобного запроса с помощью чистого языка SQL - чрезвычайно сложная задача. Более того, производительность полученного запроса вызывает сомнения. В прошлом я либо пытался применять прием select из select , либо писал PL/SQL-функцию, которая по данным из текущей строки находила предыдущую и следующую строки данных. Это работало, но очень много времени уходило на разработку запроса (приходилось писать больше кода); кроме того, расходовалось большое количество ресурсов при его выполнении.

С помощью аналитических функций это делается быстро и эффективно. Соответствующий запрос будет выглядеть так:

scott@TKYTE816> select deptno, ename, hiredate,

2 lag(hiredate, 1, null) over (partition by deptno

3 order by hiredate, ename) last hire,

4 hiredate - lag(hiredate, 1, null)

5 over (partition by deptno

6 order by hiredate, ename) days last,

7 lead(hiredate, 1, null)

8 over (partition by deptno

9 order by hiredate, ename) next hire,

10 lead(hiredate, 1, null)

11 over (partition by deptno

12 order by hiredate, ename) - hiredate days next

13 from emp

14 order by deptno, hiredate

15 /

DEPTNO ENAME HIREDATE LAST HIRE DAYS LAST NEXT HIRE DAYS NEXT

10 CLARK 09-JUN-81 17-NOV-81 161

KING 17-NOV-81 09-JUN-81 161 23-JAN-82 67



1078

Глава 12

MILLER

23-JAN-82

17-NOV-81

SMITH

17-DEC-80

02-APR-81

JONES

02-APR-81

17-DEC-80

03-DEC-81

FORD

03-DEC-81

02-APR-81

09-DEC-82

SCOTT

09-DEC-82

03-DEC-81

12-JAN-83

ADAMS

12-JAN-83

09-DEC-82

ALLEN

20-FEB-81

22-FEB-81

WARD

22-rEB-81

20-FEB-81

01-MAY-81

BLAKE

01-MAY-81

22-FEB-81

08-SEP-81

TURNER

08-SEP-81

01-MAY-81

28-SEP-81

MARTIN

28-SEP-81

08-SEP-81

03-DEC-81

JAMES

03-DEC-81

28-SEP-81

14 rows selected.

Функции LEAD и LAG можно рассматривать как способы индексации в пределах группы. С помощью этих функций можно обратиться к любой отдельной строке. Обратите внимание: в представленн1х выше результатах запись для сотрудника KING включает данные (выделены полужирным) из предыдущей строки (LASTHIRE) и последующей (NEXTHIRE). Можно получить поля предыдущих или последующих записей в упорядоченном фрагменте.

Прежде чем подробно рассматривать функции LAG и LEAD, я хотел бы сравнить этот запрос с аналогичным по результатам запросом, в котором не используются аналитические функции. Для этого я создам необходимые индексы по таблице, чтобы максимально быстро получать ответ:

create table

scott@TKYTE816>

select

object name ename, created hiredate, mod(object id,50) from all objects /

deptno

Table created.

scott@TKYTE816> alter table t modify deptno not null;

Table altered.

scott@TKYTE816> create index t idx on t(deptno,hiredate,ename)

2 /

Index created.

scott@TKYTE816> analyze table t

2 compute statistics

3 for table

4 for all indexes

5 for all indexed columns

Table analyzed.



1 ... 220 221 222 [ 223 ] 224 225 226 ... 469

© 2006 - 2025 pmbk.ru. Генерация страницы: 0
При копировании материалов приветствуются ссылки.
Яндекс.Метрика