Добавил:
Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:

Лаврентев Освоение СQЛ 2009

.pdf
Скачиваний:
63
Добавлен:
16.08.2013
Размер:
2.47 Mб
Скачать

31

Внешнее объединение не «сработало». Справа надо вставлять название той таблицы, в которой есть информация regional_group «MOSCOW», «KIEV»). Если мы заменим в последнем запросе «RIGHT JOIN» на «LEFT JOIN», внешнее объединение отработает верно:

DEMO@ORCL> SELECT l.regional_group, d.name FROM location l LEFT JOIN department d

USING (location_id) ORDER BY l.regional_group;

Отметим, что в нашей учебной базе данных не только есть regional_group, в которых нет отделов, но и есть отделы, не принадлежащие ни к какой regional_group. Запрос, который бы показал и отделы, не принадлежащие regional_group, и regional_group, не имеющие отделов, должен использовать «FULL OUTER JOIN».

DEMO@ORCL>SELECT l.regional_group, d.name, d.department_id

FROM location l FULL OUTER JOIN department d

USING (location_id) ORDER BY l.regional_group;

Q2_25. Комплексный пример использования объединений (внутренних и внешних).

32

Для отделов с номерами больше 20 извлечь информацию: фамилия служащего, его должность, номер тдела, в котором служащий работает, название отдела, место расположения отдела

DEMO@ORCL> SELECT e.last_name AS name, j.function, d.department_id , d.name AS department_name, l.regional_group

FROM employee e, department d, location l, job j WHERE e.job_id = j.job_id(+)

AND e.department_id (+) = d.department_id AND d.location_id = l.location_id

AND d.department_id>20 ORDER BY d.department_id;

II.2.7. Иерархические запросы

Q2_26. В таблице EMPLOYEE можно проследить уровни подчиненности сотрудников фирмы /1/

DEMO@ORCL> SELECT level, department_id, employee_id, manager_id,last_name, job_id, salary FROM employee

CONNECT BY PRIOR employee_id=manager_id START WITH manager_id IS NULL;

33

Для президента фирмы (KING) руководитель отсутствует (в столбце manager_id значение NULL). В запросе есть часть «START WITH manager_id IS NULL», чтобы «раскрутить» всю иерархию подчиненности, начиная с корневой строки иерархии (с президента фирмы). Если мы не укажем в запросе эту часть, запрос выведет главную иерархию, начинающуюся с KING-а, а также все возможные частные иерархии. В столбце «level» выводится уровень иерархии в «дереве» подчиненности. Для служащих с level 2 непосредственным начальником является KING. Служащие с level 3 в запросе выводятся сразу вслед за строкой своего начальника с level 2 и т.д. Часть запроса «CONNECT BY PRIOR employee_id=manager_id» определяет, что значения столбца «employee_id» являются родительскими, предшествующими (PRIOR) к дочернему столбцу «manager_id». В выводимой информации видно, что значения столбца «employee_id» располагаются выше тех же значений в столбце«manager_id». Сначала выводится, например, строка с last_name «KING», а затем только все строки со служащими, начальником которых является KING. Это и соответствует отношению при выводе информации по запросу «родитель (employee_id)» -«дочерний (manager_id)».

Если мы выполним:

DEMO@ORCL> SELECT level, department_id, employee_id, manager_id,last_name, job_id , salary FROM employee

CONNECT BY PRIOR manager_id = employee_id START WITH manager_id =7566;

то увидим, что значения столбца «manager_id» располагаются выше (PRIOR) тех же значений столбца «employee_id» . Иерархия «разворачивается» от подчиненного к начальнику. А так как у служащего с номером 7566 (JONES) два подчиненных, эта иерархия выводится дважды: сначала для подчиненного JONES-а с last_name «SCOTT», затем для подчиненного JONES-а с last_name «FORD». Это соответствует при выводе информации по запросу отношению «родитель (manager_id)» - «дочерний (employee_id)».

Q2_27. В нижеприводимом запросе /1/ используется удобное для восприятия форматирование вывода с помощью функции LPAD и псевдостолбца LEVEL Предварительно отформатируем используемый при выводе столбец, соответствующий алиасу

«tree»:

DEMO@ORCL>COL tree FORMAT A20

DEMO@ORCL> SELECT LPAD(' ', (LEVEL-1)*3)||LEVEL||' '||e.last_name AS tree, e.employee_id, e.manager_id, j.function FROM employee e, job j

WHERE e.job_id = j.job_id

CONNECT BY PRIOR e.employee_id=e.manager_id START WITH e.last_name='KING';

34

Q2_28. Из дерева иерархии сотрудников можно выделить отдельные ветви. Выделим строки, связанные с отделом 20

DEMO@ORCL> SELECT LPAD(' ',(LEVEL-1)*3)||LEVEL||' '||last_name AS tree, employee_id, manager_id , job_id

FROM employee

CONNECT BY PRIOR employee_id = manager_id AND department_id = 20

START WITH manager_id IS NULL;

Q2_29 Показать все ветви части общего дерева иерархии, выделенной предыдущим запросом, с указанием длины пути от родителя к потомку в этой ветви и самого пути от начальника к подчиненному для этой ветви /4/

DEMO@ORCL>SELECT last_name "Employee", CONNECT_BY_ROOT last_name "Manager", LEVEL-1 "Pathlen", SYS_CONNECT_BY_PATH(last_name, '/') "Path"

FROM employee

WHERE LEVEL > 1 and department_id = 20 CONNECT BY PRIOR employee_id = manager_id;

35

Выведены все возможные ветви для сотрудников отдела 20: SCOTT →ADAMS (одна срока), FORD → SMITH (одна строка), JONES и четыре его подчиненных (четыре строки), KING и пять его подчиненных из 20-го отдела (пять строк). Функция SYS_CONNECT_BY_PATH(last_name, '/') в иерархических запросах формирует путь от начальника к подчиненному, а часть запроса «CONNECT_BY_ROOT last_name "Manager"» позволяет вывести из нашей части (для отдела 20) общего дерева иерархии фирмы всех возможных начальников.

Q2_30. Иерархический запрос позволяет агрегировать данные по ветвям дерева. Вычислим нарастающим итогом по всем ветвям дерева от подчиненных к начальнику зарплату служащих отдела 20, начиная с подчиненных/4/:

DEMO@ORCL>SELECT name, SUM(salary) "Total_Salary" FROM

(SELECT CONNECT_BY_ROOT last_name as name, Salary FROM employee

WHERE department_id = 20

CONNECT BY PRIOR employee_id = manager_id) GROUP BY name;

II.3. Функции Oracle SQL

Общее количество SQL функций в Otacle10g – более двухсот (см. раздел документации

Oracle10g D:\Ora10.2_.doc\server.102\b14200\functions001.htm). По типу функции разделяются на числовые, символьные, функции для работы с датами, функции общего сравнения, функции преобразования, агрегатные функции, аналитические функции, функции для работы с большими объектами и др.

Рассмотрим более подробно некоторые типы функций.

II.3.1. Некоторые символьные функции

Q3_1. Выведем на нижнем регистре названия отделов

DEMO@ORCL>SELECT LOWER(name) FROM department;

36

Вывод на верхнем регистре реализуется функцией UPPER(название столбца или текст)

Q3_2. Выведем названия отделов так, чтобы первая буква названия выводилась на верхнем регистре, используя функцию INITCAP()

DEMO@ORCL>SELECT INITCAP(LOWER(name)) FROM department;

Q3_3. Дополним выводимые названия отделов слева символом «_» так, чтобы при этом выводимое название вместе с добавленными символами имело 20 символов

DEMO@ORCL>SELECT LPAD(name, 20 ,’_’) FROM department;

Q3_4. Дополним выводимые названия отделов справа символом «*», так, чтобы при этом выводимое название вместе с добавленными символами имело 20 символов

DEMO@ORCL>SELECT RPAD(name, 20 ,'*') FROM department;

37

Q3_5. Выведем наряду с описанием продукта усеченное слева описание продукта (удалением из описания продукта начального слова «YELLOW ») только для продуктов, описание которых начинается словом «YELLOW»

demo@10g>SELECT description, LTRIM(description, 'YELLOW') AS "Shorted Description" FROM product WHERE description LIKE 'YELLOW%';

Q3_6. Выведем наряду с названием отдела усеченное справа название отдела (удалением из названия отдела завершающей части слова «ATIONS ») только для отделов, описание которых начинается буквой «O»

demo@10g>SELECT name, RTRIM(name, 'ATIONS') AS "TOPPED NAME" FROM department WHERE name LIKE 'O%';

Q3_7. Выведем среднюю часть описания продукта, начинающегося на букву «W» demo@10g>SELECT description, SUBSTR(description, 6,8) AS "Middle"

FROM product WHERE description LIKE 'W%';

Функция substr «вырезает» из описания продукта 8 букв, начиная с шестой.

Q3_8. Определим, сколько раз символ «S» встречается в названиях отделов /1/. Сделаем это за несколько шагов.

38

DEMO@ORCL>SELECT name FROM department

WHERE department_id IN(10, 20, 30, 40);

NAME

--------------

ACCOUNTING RESEARCH SALES OPERATIONS

DEMO@ORCL>SELECT length(name) FROM department

WHERE department_id IN(10,20,30,40);

LENGTH(NAME)

------------

10

8

5

10

DEMO@ORCL>SELECT translate(name,'AS','A') FROM department

WHERE department_id IN(10,20,30,40);

TRANSLATE(NAME

--------------

ACCOUNTING REEARCH ALE OPERATION

Функция translate в названии отдела, содержащемся в столбце name, заменяет символы из этого названия, если они встречаются в первом списке ('AS') на символы из второго списка ('A'). Причем для символа на первой позиции в первом списке для замены берется символ на первой позиции из второго списка, для символа на второй позиции из первого списка должен браться символ на второй позиции из второго списка и т.д. При такой замене 'A' "меняется" на 'A', 'S' меняется на ..., а вот для 'S' нет замены, так как список замен включает только одну букву 'A' и на второй позиции списка замен нет букв. В этом случае (когда нет замены) Oracle убирает букву 'S' из названия отдела, содержащегося в столбце name.

DEMO@ORCL>SELECT LENGTH(TRANSLATE(name,'AS','A')) AS "Длина без символа S" FROM department

WHERE department_id in(10, 20, 30, 40);

Длина без символа S

-------------------

10

7

3

9

11 строк выбрано.

DEMO@ORCL>SELECT LENGTH(name) - LENGTH(TRANSLATE(name,'AS','A')) AS "Число букв S" FROM department

WHERE department_id in(10, 20, 30, 40);

39

Число букв S

------------

0

1

2

1

II.3.2. Некоторые функции даты и времени

Таблица II.2. Наиболее распространенные функции обработки календарных дат

Функция

Возвращаемое

Пример использования

Результат

 

значение

 

 

 

 

 

 

sysdate

Текущие дата и

SELECT sysdate

28-FEB-99 (при вызове 28

 

время

FROM dual;

февраля 1999 года)

 

 

 

 

last_day

Последний день

SELECT last_day(sysdate)

31-MAR-99 (при вызове

 

месяца

FROM dual;

12 марта 1999 года)

 

 

 

 

add_months(d,n)

Добавляет к дате d

SELECT add_months(sysdate,2)

18-MAY-99 (при вызове

 

(или вычитает из

FROM dual;

18 марта 1999 года)

 

нее) n месяцев

 

 

 

 

 

 

months_between(f,

Число месяцев

SELECT

13 (при вызове в апреле

s)

между датой f и

months_between(sysdate,

1998 года)

 

датой s

'12-MAR-99')

 

 

 

FROM dual;

 

next_day(d,day)

Ближайший

SELECT

05-JAN-98 (при вызове 30

 

указанный день

next_day(sysdate,'Monday')

декабря 1997 года)

 

недели day после

FROM dual;

 

 

даты d

 

 

Для работы с функциями обработки календарных дат (табл. II.2) надо знать собственно форматы представления дат. Поэтому далее приведем форматы представления дат в

Oracle (табл. II.3).

Таблица II.3. Наиболее распространенные форматы представления дат

Функция

Возвращаемое значение

Пример использования

Результат

 

 

 

 

Y, YY

Последние одна, две или три

SELECT to_char(sysdate,'YYY')

999 (для всех дней

или YYY

цифры календарного года

FROM dual;

1999 года)

 

 

 

 

SYEAR

Полный номер календарного года;

SELECT to_char(sysdate,

TWO THOUSAND

или

при использовании SYEAR перед

'SYEAR')

EIGHT (для вызова

YEAR

датами до н.э. ставится минус

FROM dual;

в 2008 г.)

 

 

 

 

Q

Квартал года (первый квартал

SELECT to_char(sysdate,'Q')

2 (для всех дней

 

продолжается с января по март)

FROM dual;

июня)

 

 

 

 

MM

Номер месяца (в формате 01-12,

SELECT to_char(sysdate,'MM')

12 (для всех дней

 

где 12 соответствует декабрю)

FROM dual;

декабря)

 

 

 

 

RM

Номер месяца римскими цифрами

SELECT to_char(sysdate,'RM')

IV (для всех дней

 

 

FROM dual;

апреля)

 

 

 

 

Month

Месяц в виде строки из девяти

SELECT to_char(sysdate, 'Month')

May и шесть

 

символов

FROM dual;

пробелов (для всех

 

 

 

дней мая)

 

 

 

 

 

 

 

40

 

 

 

 

WW

Номер недели в году

SELECT to_char(sysdate,'WW')

24 (при вызове 13

 

 

FROM dual;

июня 1998 года)

 

 

 

 

W

Номер недели в месяце

SELECT to_char(sysdate,'W')

1 (при вызове 1

 

 

FROM dual;

октября 1995 года)

 

 

 

 

DDD

Порядковый номер дня в году: 1

SELECT to_char(sysdate,'DDD')

363 (при вызове 29

 

января — день номер 001, 1

FROM dual;

декабря 1999 года)

 

февраля — 032 и т.д.

 

 

 

 

 

 

DD

День месяца

SELECT to_char(sysdate,'DD')

04 (при вызове 4

 

 

FROM dual;

октября)

 

 

 

 

D

День недели (в формате 1-7)

SELECT to_char(sysdate,'D')

1 (при вызове 14

 

 

FROM dual;

марта 1999 года)

 

 

 

 

DY

Сокращенное название дня недели

SELECT to_char(sysdate,'DY')

SUN (при вызове 28

 

 

FROM dual;

марта 1999 года)

 

 

 

 

НН или

Час по 12-часовой системе

SELECT to_char(sysdate,'HH')

02 (в момент времени

НН12

 

FROM dual;

02:08, т.е. в 2 часа 8

 

 

 

минут после

 

 

 

полуночи)

 

 

 

 

НН24

Час по 24-часовой системе

SELECT to_char(sysdate,'HH24')

14 (в 2 часа 8 минут

 

 

FROM dual;

пополудни, т.е. в

 

 

 

14:08)

 

 

 

 

Ml

Минуты (0-59)

SELECT to_char(sysdate,'MI')

17 (в 16:17, т.е. в 4

 

 

FROM dual;

часа 17 минут

 

 

 

пополудни)

 

 

 

 

SS

Секунды (0-59)

SELECT to_char(sysdate,'SS')

22 (в момент времени

 

 

FROM dual;

11:03:22)

 

 

 

 

Следует привести команды, полезные при заполнении таблиц информацией из SQL скрипта, применять которые нужно, если настройки даты на своем компьютере отличаются от формата даты в скриптах. Параметры настройки даты на своем компьютере определяют командой

DEMO@ORCL>SELECT * FROM nls_session_parameters

WHERE parameter IN ('NLS_LANGUAGE', 'NLS_DATE_FORMAT');

PARAMETER

VALUE

------------------------------

---------------------------------

NLS_LANGUAGE

RUSSIAN

NLS_DATE_FORMAT

DD.MM.RR

Такие настройки даты на компьютере автора. В скриптах же заполнения таблиц схемы «DEMO» формат даты «DD-MON-YYYY», причем месяц пишется на английском («JUN», «FEB» и т.д.). Поэтому автору для успешного заполнения таблиц схемы демо необходимо выполнить две команды:

ALTER SESSION SET NLS_DATE_FORMAT='DD-MON-YYYY'; ALTER SESSION SET NLS_LANGUAGE='AMERICAN';

Эти две команды присутствуют в начале скрипта создания предметной области DEMO.

Q3_9. Определим в днях разницу дат заказа покупки (order_date) покупателем и ее оплаты (ship_date)

DEMO@ORCL>SELECT (ship_date - order_date) AS "Задержка оплаты"