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

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

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

61

DEMO@ORCL>DELETE FROM s_grade WHERE grade_id=5;

1 строка удалена.

DEMO@ORCL>SELECT * FROM s_grade;

Создадим точку 1 сохранения транзакций

DEMO@ORCL>SAVEPOINT poin1;

Точка отката создана.

DEMO@ORCL>DELETE FROM s_grade WHERE grade_id=4;

1 строка удалена.

DEMO@ORCL>SELECT * FROM s_grade;

Создадим точку 2 сохранения транзакций

DEMO@ORCL>SAVEPOINT poin2;

Точка отката создана.

DEMO@ORCL>DELETE FROM s_grade;

3 строк удалено.

DEMO@ORCL>SELECT * FROM s_grade;

Строки не выбраны

Вернемся к точке сохранения транзакции

DEMO@ORCL>ROLLBACK TO poin2;

Откат завершен

DEMO@ORCL>SELECT * FROM s_grade;

62

DEMO@ORCL>ROLLBACK TO poin1;

Откат завершен

DEMO@ORCL>SELECT * FROM s_grade;

DEMO@ORCL>commit;

II.5. Создание и изменение структуры таблиц средствами DDL

Q5_1. Создание таблицы department1 и заполнение ее данными:

DEMO@ORCL>CREATE TABLE department1( department_id NUMBER(2,0) NOT NULL, name VARCHAR2(14) NULL,

location_id NUMBER(3,0) NULL, CHECK (department_id IS NOT NULL), PRIMARY KEY (department_id),

FOREIGN KEY (location_id) REFERENCES location(location_id) );

Таблица создана.

DEMO@ORCL>INSERT INTO department1 (SELECT * FROM department);

13 строк создано.

Создание таблицы employee1 заполнение ее данными:

DEMO@ORCL>CREATE TABLE employee1( employee_id NUMBER(4,0) NOT NULL, last_name VARCHAR2(15) ,

first_name VARCHAR2(15) , middle_initial VARCHAR2(1), job_id NUMBER(3,0), manager_id NUMBER(4,0), hire_date DATE,

salary NUMBER(7,2), commission NUMBER(7,2),

department_id NUMBER(2,0) NOT NULL,

CHECK (department_id BETWEEN 10 AND 99) DISABLE, PRIMARY KEY (employee_id),

FOREIGN KEY (job_id) REFERENCES job(job_id),

63

FOREIGN KEY (manager_id) REFERENCES employee(employee_id), FOREIGN KEY (department_id) REFERENCES department1(department_id), CONSTRAINT lst_name_dept_id UNIQUE(last_name,department_id)

);

Таблица создана.

DEMO@ORCL>INSERT INTO employee1 (SELECT * FROM employee);

32 строк создано.

В созданной таблице один столбец (employee_id) является primary key и три столбца

(job_id, manager_id, department_id) образуют три разных foreign key по одному столбцу в каждом. Кроме того определено ограничение целостности (constraint) lst_name_dept_id, требующее уникальности фамилии служащего в отделе. Столбцы, для которых указано «NOT NULL», должны быть заполнены информацией при вставке строк в таблицу. Ограничение CHECK задает диапазон значений department_id от 10 до 99. Это ограничение отключено (…DISABLE).

Q5_2. Добавим новые столбцы в таблицу employee1

DEMO@ORCL>ALTER TABLE employee1 ADD birth_day DATE;

Таблица изменена.

DEMO@ORCL>ALTER TABLE employee1 ADD E_SEX CHAR(1) DEFAULT ('M');

Q5_3. Удалим столбцы из таблицы employee1

DEMO@ORCL>ALTER TABLE employee1 DROP COLUMN middle_initial;

Таблица изменена.

DEMO@ORCL>ALTER TABLE employee1 DROP COLUMN commission;

Таблица изменена.

DEMO@ORCL>DESC employee1

Имя

Пусто?

Тип

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

--------

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

EMPLOYEE_ID

NOT NULL

NUMBER(4)

LAST_NAME

 

VARCHAR2(15)

FIRST_NAME

 

VARCHAR2(15)

E_SEX

 

CHAR(1)

JOB_ID

 

NUMBER(3)

MANAGER_ID

 

NUMBER(4)

HIRE_DATE

 

DATE

SALARY

 

NUMBER(7,2)

DEPARTMENT_ID

NOT NULL

NUMBER(2)

BIRTH_DAY

NOT NULL

DATE

Q5_4. Добавим ограничение целостности к столбцу e_sex

DEMO@ORCL>ALTER TABLE employee1 ADD CONSTRAINT check_sex check(e_sex in ('M','F'));

Таблица изменена.

Q5_5. Задействуем отключенное при создании таблицы employee1 ограничение целостности для столбца department_id, которым устанавливается диапазон значений от 10 до 99. Для такого задействования нам надо определить имя этого ограничения,

64

которое Oracle присваивает автоматически при создании таблицы. Для этого извлечем данные из таблицы словаря Oracle, предварительно отформатировав один из ее столбцов:

DEMO@ORCL>COL search_condition FORMAT A40

DEMO@ORCL>SELECT constraint_name, search_condition, status FROM user_constraints WHERE table_name='EMPLOYEE1';

Теперь можно «включить» ограничение SYS_C006046 (как видно из результата запроса, ограничению с таким именем соответствует фраза «DEPARTMENT_ID BETWEEN 10 AND 99»):

DEMO@ORCL>ALTER TABLE employee1 MODIFY CONSTRAINT SYS_C006046 ENABLE;

Таблица изменена Чтобы убедиться, что ограничение включено, повторим запрос к словарю:

DEMO@ORCL>SELECT constraint_name, search_condition, status FROM user_constraints WHERE table_name='EMPLOYEE1';

Q5_6. Удалим добавленное ограничение целостности check_sex

DEMO@ORCL>ALTER TABLE employee1 DROP CONSTRAINT check_sex;

Таблица изменена.

Q5_7. Скорректируем максимальную длину столбца last_name

DEMO@ORCL>ALTER TABLE employee1 MODIFY (last_name VARCHAR2(30));

Таблица переименована.

Q5_8. Переименование таблицы

DEMO@ORCL>RENAME employee1 TO employee2;

Таблица переименована.

Q5_9. Переименование столбца таблицы employee2

DEMO@ORCL>ALTER TABLE employee2 RENAME COLUMN e_sex TO sex;

Таблица изменена.

65

Q5_10. Удалим таблицы department1, employee2: DEMO@ORCL>DROP TABLE department1;

DROP TABLE department1

*

ошибка в строке 1:

ORA-02449: уникальный/первичный ключ в таблице, на которую ссылаются по внешнему ключу

На таблицу department1 ссылаются записи таблицы employee2 (переименованной таблицы EMPLOYEE1), поэтому команду удаления таблицы DEPARTMENT1 надо писать иначе:

DEMO@ORCL>DROP TABLE department1 CASCADE CONSTRAINT;

Таблица удалена.

DEMO@ORCL>DROP TABLE employee2;

Таблица удалена.

Q5_11. Опция EXCEPTION INTO

Создадим таблицу, которую будем использовать для занесения информации о строках, нарушающих ограничение целостности

DEMO@ORCL> CREATE TABLE my_exceptions ( row_id ROWID,

owner VARCHAR2(30), table_name VARCHAR2(30), constraint VARCHAR2(30));

Нарушать ограничение целостности будем для таблицы s_grade. Текущее ее содержимое: DEMO@ORCL>SELECT * FROM s_grade;

Продублируем информацию в ней:

DEMO@ORCL> INSERT INTO s_grade (SELECT * FROM s_grade);

4 строк создано.

DEMO@ORCL>SELECT * FROM s_grade;

Видно, что в столбце grade_id значения повторяются.

Скорректируем таблицу s_grade, сделаем попытку определить столбец grade_id, как primary key. Часть команды «…exseption into my_exseption» указывает Oracle, куда помещать информацию о тех строках таблицы, из-за которых корректировка невозможна, т.е. столбец grade_id не удается определить, как primary key.

66

DEMO@ORCL>alter table S_GRADE add constraint pk_grade_id primary key(grade_id) exceptions into MY_EXCEPTIONS;

alter table S_GRADE add constraint pk_grade_id primary key(grade_id)

*

ошибка в строке 1:

ORA-02437: невозможно подтвердить (DEMO.PK_GRADE_ID) - нарушен первичный ключ

Так как значения столбца grade_id повторяются, выполнить команду невозможно, Oracle выдает сообщение об ошибке и помещает в таблицу MY_EXSEPTION строки, из-за которых эта ошибка появляется.

DEMO@ORCL>SELECT * FROM my_exceptions;

Q5_12. Тип LONG в документации Oracle определяется устаревшим типом и оставляется в целях использования для обратной совместимости с прежними версиями Oracle. Таблица user_constraints, из которой мы выше извлекали информацию имеет столбец search_condition типа LONG.

Теперь попробуем извлечь из таблицы user_constraints информацию, воспользовавшись условием WHERE для столбца search_condition типа LONG:

DEMO@ORCL>SELECT * FROM user_constraints WHERE search_condition LIKE '%department%';

WHERE search_condition LIKE '%department%'

*

ошибка в строке 2:

ORA-00932: несовместимые типы данных: ожидается NUMBER, получено LONG.

Причем функции преобразования типов ( TO_LOB, TO_CHAR и т.д.) здесь не помогают. Прямое преобразование типа LONG в тип CLOB не проходит, так как во-первых user_constraints является представлением словаря, а во-вторых структуру объектов словаря, «хозяйства» администратора базы данных менять не рекомендуется, да и привилегии на это нужны особые, которых у пользователя demo нет:

DEMO@ORCL>ALTER TABLE user_constraints MODIFY (search_condition CLOB); alter table user_constraints modify (search_condition CLOB)

*

ошибка в строке 1:

ORA-00942: таблица или представление пользователя не существует

Для того чтобы запросы вышеприведенного типа обрабатывались (SELECT * FROM user_constraints WHERE search_condition LIKE '%department%';), возможен такой вариант преобразования типа LONG в тип CLOB:

DEMO@ORCL>CREATE TABLE my_user_constraints ( constraint_name VARCHAR2(30),

67

table_name VARCHAR2(30), search_condition CLOB);

Таблица создана.

DEMO@ORCL>INSERT INTO my_user_constraints

(SELECT constraint_name, table_name, TO_LOB(search_condition) FROM user_constraints);

83 строк создано.

Без функции преобразования TO_LOB() Oracle не позволяет переносить тип LONG в другой столбец такого же типа или типа CLOB.

DEMO@ORCL> INSERT INTO my_user_constraints (SELECT constraint_name, table_name, search_condition FROM user_constraints);

(SELECT constraint_name, table_name,search_condition

*

ошибка в строке 2:

ORA-00997: неверное использование типа данных LONG

Теперь тот запрос, который на столбце типа LONG выдавал ошибку, со столбцом типа CLOB проходит:

DEMO@ORCL>SELECT * FROM my_user_constraints

WHERE search_condition LIKE '%department%';

II.6. Другие объекты базы данных

Q6_1. Создание представления

DEMO@ORCL>CREATE OR REPLACE VIEW emp_dept AS

SELECT e.employee_id, e.last_name, department_id, d.name AS department

FROM employee e join department d USING (department_id) WHERE department_id=10;

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

Вставка значений в это представление не получится. Нельзя изменить более одной таблицы посредством связанного представления. Если мы попытаемся вставить только один столбец одной таблицы (employee_id), Oracle потребует вставки foreign key

68

(department_id) и т.д. для всех вариантов вставки столбцов. Изменение в одном варианте

(UPDATE emp_dept SET employee_id WHERE employee_id…..) возможно, но только для строк служащего, у которого нет подчиненных.

Q6_2. Создание представления с опцией READ ONLY, запрещающей insert, update, delete с базовой таблицей, на основе которой создано представление, через это представление

DEMO@ORCL>CREATE OR REPLACE VIEW emp_v1 AS SELECT employee_id,last_name, (salary+NVL(commission, 0)) AS

"Общая зарплата_отдела", department_id FROM employee WITH READ ONLY;

Q6_3. Использование представлений для отработки запроса

Использование представлений для отработки запроса нередко «спасает» студентов на контрольной работе по SQL. Рассмотрим такой запрос:

«Получите имена всех заказчиков товара, которые оформляли заказы два или более раза в 1990 году, год заказа, а также фамилии торговых представителей для этих заказчиков. Выводимый список упорядочить по имени заказчика и году продаж».

Посмотрим, как этот запрос можно отработать с использованием представлений. Отметим, что:

идентификатор заказчика - customer.custmer_id присутствует также в качестве FOREIGN KEY и в таблице sales_order;

имя заказчика - customer.name;

год заказа – TO_CHAR(sales_order.ship_date,'YYYY');

фамилия торгового представителя – employee.last_name.

Сначала найдем имена заказчиков, которые оформляли заказы два или более раза:

DEMO@ORCL>CREATE or replace view v1 as SELECT customer_id FROM

(SELECT customer_id, ship_date, COUNT(customer_id) AS count FROM sales_order

WHERE TO_CHAR(ship_date,'YYYY') = 1989 GROUP BY customer_id)

WHERE count>1;

DEMO@ORCL>SELECT * FROM v1;

Теперь можно сформировать результирующий запрос.

DEMO@ORCL>SELECT DISTINCT c.name, TO_CHAR(so.ship_date,'YYYY') AS year , e.last_name FROM customer c, sales_order so, employee e

WHERE c.customer_id=so.customer_id AND c.salesperson_id=e.employee_id

AND e.job_id=(SELECT job_id FROM job WHERE function='SALESPERSON')

69

AND c.customer_id IN (select customer_id FROM v1) AND TO_CHAR(so.ship_date,'YYYY') = 1989

order by c.name, year;

Осталось освободиться от v1 в результирующем запросе.

DEMO@ORCL>SELECT DISTINCT c.name, TO_CHAR(so.ship_date,'YYYY') AS year , e.last_name FROM customer c,sales_order so,employee e

WHERE c.customer_id=so.customer_id AND c.salesperson_id=e.employee_id

AND e.job_id=(SELECT job_id FROM job WHERE function='SALESPERSON') AND c.customer_id IN (

SELECT customer_id FROM

(SELECT customer_id, ship_date, COUNT(customer_id) AS count FROM sales_order

WHERE TO_CHAR(ship_date,'YYYY') = 1989 GROUP BY customer_id)

WHERE count>1)

AND TO_CHAR(so.ship_date,'YYYY') = 1989 ORDER BY c.name, year;

Q6_4. Удалим представление emp_dept. DEMO@ORCL>DROP VIEW emp_dept;

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

Q6_5. Создадим индекс по столбцу regional_group таблицы location DEMO@ORCL>CREATE INDEX i_location_name ON location(regional_group);

Индекс создан.

Теперь запросы к таблице location могут выполняться с использованием этого индекса, если в условии запроса используется столбец regional_group, например

DEMO@ORCL>SELECT * FROM location WHERE regional_group like 'N%';

Q6_6. Удаление индексов

DEMO@ORCL> DROP INDEX i_location_name;

Индекс удален.

Q6_7. Создадим кластер для таблиц location, department DEMO@ORCL>CREATE CLUSTER loc_dept (location_id NUMBER(3))

storage (initial 100k next 50k);

Кластер создан.

DEMO@ORCL>CREATE TABLE department1( department_id NUMBER(2) NOT NULL,

70

name VARCHAR2(13), location_id NUMBER(3),

CONSTRAINT department_id_pk PRIMARY KEY (department_id)) CLUSTER loc_dept(location_id);

Таблица создана.

Вотличие от создания обычной таблицы при создании таблицы кластера указывается,

ккакому кластеру таблица принадлежит и по какому столбцу построен кластер.

DEMO@ORCL>CREATE TABLE location1( location_id NUMBER(3) NOT NULL, regional_group VARCHAR2(20),

CONSTRAINT location_id_pk PRIMARY KEY (location_id)) CLUSTER loc_dept(location_id);

Таблица создана.

Создаем индекс кластера:

DEMO@ORCL>CREATE INDEX idx_loc_dept ON CLUSTER loc_dept;

Индекс создан.

Заполним таблицы данными:

DEMO@ORCL>INSERT INTO department1 (SELECT * FROM department);

11 строк создано.

DEMO@ORCL>INSERT INTO location1 (SELECT * FROM location);

4 строк создано.

Теперь при отработке запросов, включающих во фразе «…FROM» обе таблицы кластера, Oracle будет отрабатывать эти запросы, извлекая данные из струкутуры кластера.

Q6_8. Удаление кластера, всех таблиц, принадлежащих кластеру и всех ограничений целостности, принадлежащих ему

DEMO@ORCL>DROP CLUSTER loc_dept INCLUDING TABLES CASCADE CONSTRAINTS;

Кластер удален.

Q6_9. Создадим public синоним для таблицы department:

DEMO@ORCL>CREATE PUBLIC SYNONYM dept FOR department;

CREATE SYNONYM dept FOR department

*

ошибка в строке 1:

ORA-01031: привилегий недостаточно

Сообщение об ошибке указывает об отсутствии у пользователя DEMO привилегии создавать синонимы. Из другого окна SQL*Plus соединимся пользователем SYSTEM (DBA) и выполним этим пользователем команду: CREATE PUBLIC SYNONYM dept for demo.department;. Теперь к таблице DEPARTMENT пользователю DEMO можно обращаться по более короткому имени синонима:

DEMO@ORCL>SELECT * FROM dept;