ВВЕДЕНИЕ И ОСНОВНЫЕ ОПРЕДЕЛЕНИЯ. .................................................................................................. 2 БАЗА ДАННЫХ ........................................................................................................................................................... 2 ПЕРВИЧНЫЙ КЛЮЧ ................................................................................................................................................... 3 ВНЕШНИЙ КЛЮЧ ....................................................................................................................................................... 4 ССЫЛОЧНАЯ ЦЕЛОСТНОСТЬ ..................................................................................................................................... 5 РАЗРАБОТКА БАЗ ДАННЫХ И ПРИЛОЖЕНИЙ. ............................................................................................................. 5 ПОСТАНОВКА ЗАДАЧИ. ....................................................................................................................................... 6 ОПИСАНИЕ ПРЕДМЕТНОЙ ОБЛАСТИ ......................................................................................................................... 6 ФИЗИЧЕСКАЯ МОДЕЛЬ ДАННЫХ ............................................................................................................................... 8 ОПИСАНИЕ СЕМАНТИКИ ПОЛЕЙ ............................................................................................................................... 8 ИНТЕРФЕЙС ПРОГРАММЫ ......................................................................................................................................... 9 СРЕДА APEX. .......................................................................................................................................................... 10 ЯЗЫК SQL ................................................................................................................................................................ 11 ЛАБОРАТОРНАЯ РАБОТА 1. ВЫБОРКИ ИЗ ОДНОЙ ТАБЛИЦЫ ................................................................................... 11 ЛАБОРАТОРНАЯ РАБОТА 2. СОЕДИНЕНИЕ ТАБЛИЦ. ................................................................................................ 14 ЛАБОРАТОРНАЯ РАБОТА 3. ФУНКЦИИ. ................................................................................................................... 15 ЛАБОРАТОРНАЯ РАБОТА 4. ПОДЗАПРОСЫ. ............................................................................................................ 16 ЛАБОРАТОРНАЯ РАБОТА 5. ГРУППИРОВКИ............................................................................................................. 17 ЛАБОРАТОРНАЯ РАБОТА 6. DML-КОМАНДЫ (ОПЕРАЦИИ ИЗМЕНЕНИЯ ДАННЫХ). ................................................ 18 ЛАБОРАТОРНАЯ РАБОТА 7. ОПЕРАЦИИ С ТАБЛИЦАМИ. ......................................................................................... 21 ЛАБОРАТОРНАЯ РАБОТА 8. ЭЛЕМЕНТЫ PL/SQL. ПРОЦЕДУРЫ, ФУНКЦИИ, ТРИГГЕРЫ. ......................................... 24 Введение и основные определения. База данных База данных (БД) — именованная совокупность данных, отражающая состояние объектов и их отношений в рассматриваемой предметной области. Целью разработки любой базы данных является хранение и использование информации о какой-либо предметной области. Для реализации этой цели имеются следующие инструменты: 1. Реляционная модель данных - удобный способ представления данных предметной области. 2. Язык SQL - универсальный способ манипулирования такими данными. Реляционная база данных представляет собой хранилище данных, содержащее набор двухмерных таблиц. Набор средств для управления подобным хранилищем называется реляционной системой управления базами данных (РСУБД). РСУБД может содержать утилиты, приложения, сервисы, библиотеки, средства создания приложений и другие компоненты. Любая таблица реляционной базы данных состоит из строк (называемых также записями) и столбцов (называемых также полями). В данном цикле мы будем использовать обе пары терминов. Строки таблицы содержат сведения о представленных в ней фактах (или документах, или людях, одним словом, — об однотипных объектах). На пересечении столбца и строки находятся конкретные значения содержащихся в таблице данных. Пример Тарифы на горячую и холодную воду Дата введения Номер Тариф на горячую воду 01.01.2007 1 1.80 15.05.2007 2 2.23 01.11.2007 3 3.40 01.06.2008 4 5.40 Тариф на холодную воду 1.10 1.87 2.90 3.20 Данные в таблицах удовлетворяют следующим принципам: 1. Каждое значение, содержащееся на пересечении строки и колонки, должно быть атомарным (то есть не расчленяемым на несколько значений). 2. Значения данных в одной и той же колонке должны принадлежать к одному и тому же типу, доступному для использования в данной СУБД. 3. Каждая запись в таблице уникальна, то есть в таблице не существует двух записей с полностью совпадающим набором значений ее полей. 4. Каждое поле имеет уникальное имя. 5. Последовательность полей в таблице несущественна. 6. Последовательность записей также несущественна. Каждая сущность предметной области может быть выражена как одной таблицей, так и совокупностью нескольких. Например сущность «Абоненты АО «Теплосети» (потребители горячей и холодной воды) Может быть выражена одной таблицей Абоненты Лицевой счет 4857894758 Фамилия Иванов Имя отчество Сергей Викторович 7867678868 Круглов Андрей Иванович Адрес Челябинск, Чичерина 40-12 Шершни, Ленина 12-40 Или несколькими таблицами Абоненты Лицевой счет 4857894758 7867678868 Фамилия Иванов Круглов Поселки и города Название Челябинск Шершни Мельзавод Улицы Название Чичерина Ленина Шоссе металлургов Имя отчество Город(Поселок) Ул. Сергей Викторович 1 89 Андрей Иванович 2 34 дом 40 12 Кв. 12 40 Номер 1 2 3 Номер 89 34 3 Зачем потребовалось разбивать таблицу на несколько ? 1) Уменьшение ошибок при вводе данных – если улица и поселок при вводе не набираются пользователем, а выбираются из готового справочника (таблицы названий улиц), то не будет неправильно введенных названий. 2) Исключается дублирование данных – многократного ввода одних и тех же названий для абонентов с одной улицы и одного города. 3) При изменении данных (например, переименовали улицу) не надо исправлять адреса всех абонентов с этой улицы, достаточно исправить одну строку в одной таблице названий улиц. Процесс разбивания основных сущностей на несколько таблиц называется проектированием структуры базы данных. Типичная база данных обычно состоит из нескольких связанных таблиц Первичный ключ Поскольку строки в таблице неупорядочены, нам нужна колонка (или набор из нескольких колонок) для уникальной идентификации каждой строки. Такая колонка (или набор колонок) называется первичным ключом (primary key). Первичный ключ любой таблицы обязан содержать уникальные непустые значения для каждой строки. Другие определения Ключевым элементом данных называется такой элемент, по которому можно определить значения других элементов данных. Первичный ключ - это атрибут (или группа атрибутов), которые единственным образом идентифицируют каждую строку в таблице. В таблице абонентов первичный ключ - идентификатор абонента. Зная идентификатор, мы можем узнать Фамилию абонента, адрес, лицевой счет и др. атрибуты об абоненте. Внешний ключ Колонка, указывающая на запись в другой таблице, связанную с данной записью, называется внешним ключом (foreign key). В таблице абонентов колонка «номер улицы» и «номер поселка» являются внешними ключами – ссылками на соответствующие таблицы. Подобное взаимоотношение между таблицами называется связью (relationship). Связь между двумя таблицами устанавливается путем присваивания значений внешнего ключа одной таблицы значениям первичного ключа другой. Введем таблицу «оплата» - оплата абонентами Теплосетей за горячую и холодную воду Дата оплаты 01.01.2008 12.01.2008 13.01.2008 Сумма 120.00 60.00 200.00 Лицевой счет 4857894758 4857894758 4857111111 Дата оплаты – когда абонент платил в банк или по системе «город» Сумма – сумма оплаты Лицевой счет – уникальный лицевой счет абонента Рассмотрим связь таблиц «Абоненты» и «Оплата» Лицевой счет Фамилия 4857894758 Иванов 7867678868 Круглов Первичный ключ Лицевой счет 4857894758 4857894758 4857111111 Внешний ключ Имя отчество Город(Поселок) Ул. Сергей Викторович 1 89 Андрей Иванович 2 34 Дата оплаты 01.01.2008 12.01.2008 13.01.2008 Сумма 120.00 60.00 200.00 дом 40 12 Кв. 12 40 Если мы удалим из таблицы абонентов абонента «Иванов» то оплата за воду из таблицы оплат будет неизвестно чья, и соответственно эти деньги компания «Теплосети» просто потеряет. Но при этом в таблице абонентов вполне могут присутствовать люди, ни разу не платившие по счетам. У них не будет ни одной записи в таблице оплат. Один абонент платит за воду как правило каждый месяц. Значит, в таблице оплат будет присутствовать не одна, а много записей для данного лицевого счета. Эти две таблицы связаны соотношением один-ко-многим (one-to-many relationship) или соотношением master-detail (один абонент – много оплат). Подобные соотношения между таблицами используются наиболее часто. В этом случае таблица, содержащая внешний ключ, называется detail—таблицей, а таблица, содержащая первичный ключ, определяющий возможные значения внешнего ключа, называется master-таблицей. Таблица «улицы» и «абоненты» также связаны отношением «один-ко-многим» В справочнике улиц каждая улица написана только один раз, но существует много абонентов, живущих на этой улице. Ссылочная целостность Первичный ключ любой таблицы должен содержать уникальные непустые значения для данной таблицы. Это утверждение является одним из правил ссылочной целостности (referential integrity). Некоторые (но далеко не все) СУБД могут контролировать уникальность первичных ключей. Если две таблицы связаны соотношением master-detail, внешний ключ detail-таблицы должен содержать только те значения, которые уже имеются среди значений первичного ключа master-таблицы Если СУБД контролирует корректность значений внешних ключей это означает : Невозможно присвоить внешнему ключу значение, отсутствующее среди значений первичных ключей master-таблицы. Невозможно удаление или модификация записей master-таблицы, приводящих к нарушению ссылочной целостности. При попытке пользователя нарушить ссылочную целостность СУБД сгенерирует диагностическое сообщение, обычно содержащее словосочетание foreign key violation, которое в дальнейшем может быть передано в пользовательское приложение. Разработка баз данных и приложений. При разработке базы данных обычно выделяется несколько уровней моделирования, при помощи которых происходит переход от предметной области к конкретной реализации базы данных средствами конкретной СУБД. Можно выделить следующие уровни: Сама предметная область Модель предметной области Логическая модель данных Физическая модель данных Собственно база данных и приложения Предметная область - это часть реального мира, данные о которой мы хотим отразить в базе данных. Например, в качестве предметной области можно выбрать бухгалтерию какого-либо предприятия, отдел кадров, банк, магазин и т.д. Модель предметной области. Модель предметной области - это наши знания о предметной области. Знания могут быть как в виде неформальных знаний в мозгу эксперта, так и выражены формально при помощи каких-либо средств. В качестве таких средств могут выступать текстовые описания предметной области, наборы должностных инструкций, правила ведения дел в компании и т.п Логическая модель данных. На следующем, более низком уровне находится логическая модель данных предметной области. Логическая модель описывает понятия (сущности) предметной области, их взаимосвязь, а также ограничения на данные, налагаемые предметной областью. Примеры сущностей - "сотрудник", "отдел", "проект", "зарплата". Примеры взаимосвязей между понятиями - "сотрудник числится ровно в одном отделе", "сотрудник может выполнять несколько проектов", "над одним проектом может работать несколько сотрудников". Примеры ограничений - "возраст сотрудника не менее 16 и не более 80 лет". Физическая модель данных. На еще более низком уровне находится физическая модель данных. Физическая модель данных описывает данные средствами конкретной СУБД. Физическая структура базы данных реализуется в виде таблиц, состоящих из атрибутов и записей Постановка задачи. Описание предметной области У многих людей в квартирах стоят счетчики горячей и холодной воды. Счетчики отмеряют потребление воды абонентом в кубометрах. АО «Теплосети» вводит тарифы на стоимость одного кубометра воды в рублях, отдельно на горячую и холодную воду. На данный момент технология расчетов абонентов с АО «теплосети» следующая Абонент 1 числа каждого месяца снимает показания счетчиков, установленных у него в квартире. Звонит по определенному телефону в АО теплосети , называет свой адрес и свои новые показания счетчиков. Расчетчик из АО «Теплосети» поднимает информацию по абоненту, находит старые показания, вписывает новые. Получает объем потребления воды. Умножает объем на на тариф и получает сумму, которую должен оплатить абонент. Если у абонента был долг по оплате, то этот долг прибавляется, и в счет вписывается итоговая сумма. Абоненту в итоге выставляется счет следующего вида : Лицевой счет Адрес Горячая вода Холодная вода Долги прошлых периодов Всего 4857894758 Всего оплатить Г.Челябинск, ул. Чичерина, 12-40 Объем потребления Тариф 120 куб. 5.20 руб 200 куб. 3.40 Откуда берется долг? 1434.00 Начислено 624.00 680.00 130.00 1434.00 Получив счет, абонент идет его оплачивать, например через систему город. Он может оплатить всю сумму, а может только часть. Информация о том, когда и сколько платил абонент, аккумулируетcя системой «город» в таблице следующего вида Лицевой счет 4857894758 4857894758 4857111111 Дата оплаты 01.01.2008 12.01.2008 13.01.2008 Сумма 120.00 60.00 200.00 Таблица высылается в АО «Теплосети» по электронной почте каждый день. Долг вычисляется как разница между тем что было начислено и тем, сколько оплачено. Формулировка задачи. Написать программу, которая бы позволила пользователю через Интернет вводить показания своих счетчиков по холодной и горячей воде, формировать счет для оплаты и также просмотреть всю историю своих начислений и оплат. Т.е. из описанной выше модели предметной области исключить телефон и участие расчетчика. Входные данные для программы Пользователь вводит номер лицевого счета Для дополнительно проверки (авторизации) пользователем вводится фамилия, имя отчество. Файл с оплатами вводится в систему «извне», автоматически, поэтому стрелка идет сверху. Выходные данные Счет, в том виде в котором он указан выше, т.е. сумма начисленная, долг, сумма к оплате. Декомпозируем данный процесс более конкретно Алгоритм формирования Итоговой суммы 1. Считываем показания счетчиков из последнего начисления 2. Из текущих показаний вычитаем последние, получаем объем потребления 3. Объем потребления умножаем на текущие тарифы - получаем сумму начисления в рублях 4. Из предыдущей квитанции берем сумму «Всего к оплате» 5. Из таблицы оплат вычисляем, сколько абонент заплатил за текущий период 6. «Всего к оплате» = «Всего к оплате из пред. квитанции» - «оплачено за период» + Начислено После этого вносим все новые цифры в БД Долг за прошлый период Новые показания Начислено Оплачено Всего к оплате Физическая модель данных Структура данных представлена следующими таблицами Описание семантики полей Таблица CLIENT – данные об абонентах. N_CLIENT – лицевой счет C_FIRST_NAME – имя C_SECOND_NAME – отчество C_LAST_NAME – фамилия N_SEX – идентификатор пола N_CITY – идентификатор города или поселка N_STREET – идентификатор улицы C_HOUSE – номер дома и номер корпуса N_FLAT – номер квартиры N_PHONE – номер телефона Таблица SEX – справочник пола N_SEX – идентификатор пола C_SEX – название пола Таблица STREET – справочник улиц N_STREET – идентификатор улицы C_STREET – название улицы Таблица CITY – справочник городов и поселков N_CITY – идентификатор города или поселка C_CITY – название города или поселка Таблица PAYMENT – оплата абонента N_CLIENT – лицевой счет абонента D_PAY – дата оплаты N_SUM – сумма оплаты N_SIGN – признак(1 – оплата учтена при начислении, 0 – оплата не учтена) Таблица COMPUTATION – начисления абонентов N_COMPUTATION – идентификатор начисления N_CLIENT – лицевой счет абонента D_COMPUTATION – дата начисления N_INFO_HOT – текущие показания счетчика горячей воды N_INFO_COLD – текущие показания счетчика холодной воды N_DIFFERENCE_HOT – разница текущих и предыдущих показаний счетчика горячей воды N_DIFFERENCE_COLD – разница текущих и предыдущих показаний счетчика холодной воды N_TARIFF – идентификатор тарифов на горячую и холодную воду N_SUM_HOT – начисление за горячую воду за текущий период N_SUM_COLD – начисление за холодную воду за текущий период N_DEBT – долг на начало периода N_PAY – оплата за предыдущий период N_TOTAL – итоговая сумма на конец месяца Таблица TARIFF – тарифы на горячую и холодную воду N_TARIFF – идентификатор тарифов по холодной и горячей воде D_TARIFF – дата смены тарифов на новые N_TARIFF_HOT – тариф на горячую воду (в руб.) N_TARIFF_COLD – тариф на холодную воду (в руб.) Примечание: первая буква в названии поля обозначает тип данных этого поля N – NUMBER, D – DATE, C – CHAR (VARCHAR2) Интерфейс программы Регистрация в программе пользователя Окно ввода новых показаний счетчиков По кнопке «Расчет и квитанция» производится расчет оплаты за воду. На экран выводится при этом квитанция, которую можно распечатать. Окно «Предыдущие квитанции» демонстрирует всю историю начислений и оплат абонента Среда APEX. Вход в систему http://bruteforce.csu.ac.ru:8080/apex/ Вы должны быть заведены в системе как пользователь. 1. Просмотр объектов базы данных После регистрации в системе выберите Object Browser Здесь вы можете просмотреть структуру всех таблиц и связанных с ними объектов. Не рекомендуется менять структуру или данные, пока не сдадите все задания. 2. Ввод запросов из заданий. Вернитесь в окно Home и выберите кнопку SQL, и в дальнейшем SQL commands Не забываете сохранять все ваши запросы ! Язык SQL Лабораторная работа 1. Выборки из одной таблицы SELECT [DISTINCT] {*, column [alias],...) FROM table WHERE условие; SELECT указывает, какие столбцы (* - значит все) FROM указывает, из какой таблицы WHERE указывает, какие строки AND дополнительное условие. Примеры --Найти человека с номером телефона 7992788 Select * FROM client WHERE n_phone = ‘7992788’ Проверка столбца на пустое значение --Найти абонентов, у которых не указан город проживания Select C_FIRST_NAME , C_SECOND_NAME , C_LAST_NAME FROM client WHERE N_CITY is NULL Работа с датами. Вывести месяц, год и день начислений клиента с номером 1 и с указанием долга на этот день Select to_char(D_computation,’MM’) месяц, to_char(D_computation,’YYYY’) год, to_char(D_computation,’DD’) день, n_client, n_debt From computation Where n_client = 1 Вывести оплаты за второе полугодие 2008 года абонента с номером 2 Select d_pay, n_sum From payment Where to_number(to_char(D_computation,’MM’)) > 6 And to_number(to_char(D_computation,’YYYY’)) = 2008 And n_client = 2 Задания: 1. Вывести список лицевых счетов тех абонентов, которые внесли новые показания счетчиков 1 мая 2008 года. 2. Вывести список лицевых счетов абонентов, у которых за последний период израсходовано более 100м3 горячей и 200м3 холодной воды. 3. Вывести список ФИО тех абонентов, у которых нет телефонов и не указано в каких городах они живут. 4. Вывести список ФИО тех абонентов, которые проживают в собственных домах (нет номеров квартир). 5. Вывести список ФИО тех абонентов, которые проживают в городе с идентификатором 21 и на улице с идентификатором 22. 6. Вывести абонентов мужского пола (использовать идентификатор пола равный 1), не имеющих телефонов 7. Вывести список лицевых счетов тех абонентов, у которых нет долга. Поиск по шаблону. Пример Вывести список абонентов, фамилии которых начинаются на букву А. SELECT C_FIRST_NAME , C_SECOND_NAME , C_LAST_NAME FROM client WHERE C_LAST_NAME like ‘А%’ Задания: 8. Вывести список улиц, название которых начинается на ОКТ. 9. Вывести список улиц, название которых заканчивается на АЯ 10. Вывести список абоненток с отчествами на АЛЕКС. 11. Вывести список городов начинающихся на МИ. 12. Вывести список городов, названия которых начинаются на Ч и заканчиваются на К. 13. Вывести всех абонентов, проживающих в домах с номерами начинающимися на 25. 14. Вывести всех абонентов и их лицевые счета, у которых фамилия Иванов. 15. Вывести список абонентов с именем Иван. Использование подмножеств. SELECT column FROM table WHERE column IN (va1ue1, value2, …) 16. Вывести список абонентов с улиц «Молодогвардейцев» и «Братьев Кашириных» 17. Вывести суммы оплат за январь и февраль, с 1 по 15 число 2008 года 18. Вывести список абонентов, проживающих в Троицке и Миассе (использовать идентификаторы городов) Лабораторная работа 2. Соединение таблиц. Использование нескольких таблиц в операторе SELECT позволяет выводить данные из нескольких таблиц. Например, запрос: SELECT client.c_first_name||’ ’||client.c_last_name, sex.c_sex FROM client, sex WHERE client.n_sex = sex.n_sex. Вернет список всех клиентов с указанием их пола. Обратите внимание на условие соединения. Если условие не указано, произойдет перемножение таблиц, с образованием декартова произведения множества клиентов со списком полов. В приведенном примере используется «внутренне соединение» таблиц (inner join). Оно возвращает все строки, удовлетворяющие условию WHERE. Пример. Вывести размер тарифа по которым было начисление и само начисление для Иванова за январь 2008 года. SELECT client.c_first_name||’ ’||client.c_last_name, tariff.N_TARIFF_HOT, tariff. N_TARIFF_COLD, computation.N_SUM_HOT, computation. N_SUM_COLD FROM client, computation, tariff WHERE client.n_client = computation.n_client And computation.n_tariff = tariff.n_tariff Другой тип соединения называется «внешним соединением» (outer join). Внешнее соединение возвращает все строки одной таблицы, и только те строки второй, которые удовлетворяют условию WHERE. Например, запрос: SELECT client.c_first_name||’ ’||client.c_last_name, payment.n_sum, payment.d_pay FROM client, payment WHERE client.n_client = payment.n_client (+) Вернет список всех клиентов с указанием платежей, поступивших от них. Если же клиент зарегистрирован, но ничего не платил, значения payment.n_sum и payment.d_pay будут отображаться как NULL. Здесь (+) обозначает таблицу, дополняемую NULLзначениями до полного соответствия другой. Задания: 1. Вывести адреса всех клиентов. 2. Вывести список всех клиентов из Челябинска, вносивших больше 500 рублей за оплату единовременно после 25 июня 2008 года. 3. Вывести все платежи за воду в период с 5 апреля по 30 августа 2008 года. Указать, кем был совершен платеж. 4. Вывести всех клиентов, фамилия которых начинается на букву «А», имеющих долг на сентябрь 2008 года. 5. Вывести список клиентов, проживающих в Челябинске и не имеющих долгов по оплате за сентябрь 2008 года. 6. Найти всех абонентов г. Троицка и вывести последнею сумму долга (за сентябрь), с указанием адреса и фамилии Лабораторная работа 3. Функции. Функция AVG возвращает среднее значение аргумента в выборке. Формат вызова: SELECT AVG ( expression ) FROM tables WHERE predicates; Expression может быть числовым полем (numberic field) или формулой. Функция SUM возвращает сумму аргументов в выборке. Формат вызова: SELECT SUM(expression ) FROM tables WHERE predicates; Expression может быть числовым полем (numberic field) или формулой. Функция MAX возвращает максимальное значение аргумента в выборке. Формат вызова: SELECT MAX(expression ) FROM tables WHERE predicates; Функция MIN возвращает минимальное значение аргумента в выборке. Формат вызова: SELECT MIN(expression ) FROM tables WHERE predicates; Функция COUNT возвращает количество строк, соответствующих запросу. Формат вызова: SELECT COUNT(expression ) FROM tables WHERE predicates; COUNT учитывает только те строки, для которых expression NOT NULL Пример: Посчитать количество клиентов, зарегистрированных системой: SELECT count(n_client) FROM client; или SELECT count(*) FROM client; Посчитать минимальный, максимальный и средний долг за февраль: SELECT min(n_debt), max(n_debt), avg(n_debt) FROM computation WHERE to_char(d_computation,’MONTH’) = ’ФЕВРАЛЬ’ Задания: 1. Найти клиента, зарегистрировавшегося первым. 2. Найти клиента, зарегистрировавшегося последним. 3. Найти средний рост потребления воды за февраль 2008 года в сравнении с предыдущим месяцем. 4. Посчитать сумму долга клиента Александра Иванова за январь, февраль, март и апрель 2008 года. 5. Найти минимальный и максимальный платеж, принятые системой за все время ее эксплуатации. 6. Посчитать количество мужчин и количество женщин, пользующихся системой. 7. Посчитать средний расход горячей воды клиентами из Челябинска. 8. Найти сколько всего было недоплачено клиентами из Троицка 9. Сколько мы получим прибыли за последний месяц, если увеличим тариф на 50 копеек? По сравнению со старым тарифом. Лабораторная работа 4. Подзапросы. Подзапрос применяется тогда, когда для выполнения одного запроса сначала надо выполнить другой. Пример: Вывести список всех клиентов, проживающих в городе, в котором живет самый злостный неплательщик. SELECT * -- выводим всех клиентов из этого города FROM client WHERE n_city = (SELECT n_city -- находим номер города того человека, у которого максимальный долг был FROM client cl, computation com WHERE com.n_debt= (SELECT max(n_debt) –- находим максимальный долг FROM computation) AND com.n_client=cl.n_client) Задания: 1. Вывести все платежи, с указанием даты и долга на указанную дату самого злостного неплательщика. 2. Найти сколько клиентов живет на каждой улице. 3. Вывести сумму платежей по месяцам, поступившим после даты самого большого платежа. 4. Найти адреса людей с максимальной переплатой. 5. Кем и когда был выполнен самый большой платеж? Лабораторная работа 5. Группировки Посчитать общие суммы оплат по каждому месяцу SELECT TO_char(d_day,’MM’), sum(n_sum) FROM payment WHERE TO_CHAR(d_day,’YYYY’) = ‘2008’ GROUP BY TO_char(d_day,’MM’) Вывести потребление воды по каждой улице, отсортированное в порядке убывания select c_city, ul.woda From ( select n_city, sum(n_difference_cold) woda From computation, client Where client.n_client = computation.n_client Group by n_city ) ul, city Where city.n_city = ul.n_city Order by ul.woda desc Задания. 1. Посчитать суммы потребления по каждому месяцу. 2. Посчитать количество оплаты воды по каждой улице в базе 3. Найти месяц с максимальной оплатой по всем абонентам и вывести кто больше всех в этом месяце платил 4. Найти разницу потребления воды между январем и июлем 5. Найти разницу оплат за январь и февраль 6. Вывести отчет в таком виде Тариф Текущий Текущий + 80 коп. Начислено за сентябрь 10 890 7345 12 440 7347 Будет начислено за октябрь 11 891 7145 12 890 9999 В качестве показаний счетчиков за октябрь взять AVG по 3 весенним месяцам. Лабораторная работа 6. DML-команды (операции изменения данных). Вставка данных в таблицу выполняется командой INSERT. Эта команда позволяет вставлять в таблицу как одну запись, так и множество записей, формируемых запросом. Формат вызова: - для вставки одной записи INSERT INTO table (column-1, column-2, . . . column-n) VALUES (value-1, value-2, . . . value-n); - для вставки нескольких строк INSERT INTO table1 (column-1, column-2, . . . column-n) SELECT column-1, column-2, . . . column-n FROM table2 WHERE predicates Пример. 1. Вставить новый тариф на сегодняшнюю дату Insert into tariff( D_TARIFF , N_TARIFF_HOT , N_TARIFF_COLD ) Values( SYSDATE, 7.50, 6.50); Пример: INSERT INTO client (c_first_name, c_last_name, c_second_name, n_city, n_street, c_house, n_flat, n_phone) SELECT ‘Иван’, ‘Иванов’, ‘Иванович Бюль-Бюль Оглы’, city.n_city, street.n_street, ‘129д’, 422, 0 FROM city, street WHERE city.c_city like ‘%ЧЕЛЯБИНСК’ AND street.c_street like ‘%КАШИРИНЫХ’; добавит в таблицу запись о старом админе, прописанном в аудитории 422 в ЧелГУ. В жизни такой запрос не применяется, т.к. может быть несколько строк, удовлетворяющих условиям запроса, и тогда зарегистрируется несколько людей. Задания: 1Добавить какую-нибудь улицу в справочник. Информация должна соответствовать общему формату данных. 2. Добавить какой-нибудь город или село в справочник. Информация должна соответствовать общему формату данных. 3. Добавить новый тариф расчета платежей на дату ровно на месяц раньше самого первого тарифа. 4. Добавить себя в базу как клиента. 5. Добавить для себя столько записей в таблицу начислений, сколько различных дат в ней есть, и поставить показатели счетчиков во все записи (использовать среднее значение показаний за все периоды). В качестве идентификатора клиента использовать n_client, который система присвоит Вам, как клиенту. Изменение данных в таблице осуществляется командой UPDATE. Формат вызова: UPDATE table SET column = expression WHERE predicates; ! expression может также быть формулой с участием column Например, команда: UPDATE tariff SET n_tariff_hot = 9.99 WHERE n_tariff_hot = 10; изменит цену 1 кубометра горячей воды с 10 рублей на 9.99 рублей, во всех тарифах, где он раньше стоил 10 рублей. Условие WHERE ограничивает число изменяемых строк, так что можно критическим образом изменить записи во всей таблице, если неправильно указать условие. Использование с подзапросом. Проставить в computation тариф, максимальный на дату начисления update computation com set n_tariff = ( select n_tariff from tariff where d_tariff = ( select max(d_tariff) as d from tariff where d_tariff <= com.d_computation ) ) exists означает условие что указанный подзапрос возвращает хотя бы одну строку. Задания: 1. В самый последний тариф закралась ошибка: цена 1 кубометра холодной воды оказалась на 10% выше. Исправьте ситуацию. 2. Изменить символьное значение пола в таблице sex: «М» заменить на «МУЖ», «Ж» заменить на «ЖЕН». 3. Во всех записях таблицы computation, которые относятся к Вам, пересчитать данные полей n_difference_hot и n_difference_cold по формуле: новое значение = текущий показатель – показатель прошлого месяца. 4. Изменить стоимость израсходованной горячей и холодной воды в условиях пункта 3. Удаление данных из таблицы совершается командой DELETE. Формат вызова: DELETE FROM table WHERE predicates; Например, команда: DELETE FROM street WHERE c_street like ‘ЧУГУЕ%’; удалит из списка улиц все улицы, начинающиеся с «Чугуе». Часто задаваемый вопрос: как удалить записи из одной таблицы, основываясь на данных из другой? Ответ: если не использовать EXISTS, то никак. Например: DELETE FROM client WHERE NOT EXISTS (select payment.n_pay from payment where payment.n_client = client.n_client); Такой запрос используется, чтобы удалять «клиентов-призраков», т.е. зарегистрированных пользователей, которые не пользовались системой. Задания: 1. Удалить самый старый тариф. 2. Удалить дублирующиеся записи о клиентах (сначала написать SELECT-запрос, находящий близнецов, отладить его, а потом использовать в DELETE-команде). Указания к выполнению. Клиентов считать одинаковыми если у них совпадает пол и ФИО. для того чтобы удалить дублирующихся клиентов нужно удалить подчиненные записи на них из других таблиц Лабораторная работа 7. Операции с таблицами. CREATE TABLE Создать таблицу с описанием полей можно командой CREATE TABLE. Формат вызова: CREATE TABLE table_name ( column1 datatype null/not null, column2 datatype null/not null, ... table_constraints ); datatype = один из типов данных, специфичных для Oracle (VARCHAR2, CHAR, NUMBER, DATE и т.д.). Спецификатор null/not null показывает, может ли поле принимать значение NULL. Например, команда: CREATE TABLE CLIENT ( N_CLIENT NUMBER not null, C_FIRST_NAME VARCHAR2(100) not null, C_SECOND_NAME VARCHAR2(100) not null, C_LAST_NAME VARCHAR2(100) not null, N_SEX NUMBER, N_CITY NUMBER, N_STREET NUMBER, C_HOUSE VARCHAR2(20), N_FLAT VARCHAR2(10), N_PHONE NUMBER(20) ); создает таблицу клиентов в таком виде, в каком она есть в учебной базе. Создать таблицу можно на основе уже существующей. При этом копируются все ограничения и внешние ключи. Синтаксис такого вызова: CREATE TABLE new_table AS (SELECT column_1,…, column_n | * FROM old_table); Создание ограничения. Ограничение (constraint) служат средствами поддержки целостности. Совершенно необходимо создавать ограничения на первичный ключ. Ограничения внешнего ключа не позволяют удалить записи при наличии подчиненных записей в других таблицах. Ограничения создаются добавлением в вызов CREATE TABLE выражения CONSTRAINT constraint_name constraint_type (constraint_column_name); constraint_name – тип ограничения. PRIMARY KEY – ограничение типа «первичный ключ». UNIQUE – ограничение типа «уникальное значение». Задание: Необходимо переделать справочник городов. Новый справочник должен содержать поле ТИП_НАСЕЛЕННОГО_ПУНКТА. Создайте новую таблицу при помощи команды CREATE TABLE. Скопировать в нее данные из старой таблицы. Не забудьте указать ограничение типа «первичный ключ». Внимание: 1) в старом справочнике тип населенного пункта указан одной буквой перед названием. Если для некоторых записей это не выполняется, тип должен вноситься как NULL. 2) Если при создании таблицы первичный ключ не указывали нужно добавить соответствующий констрант для новой таблицы: alter table <table_name> add constraint <constrant_name> primary key (<column_name>); DROP TABLE Удалить таблицу можно командой DROP TABLE. Формат вызова: DROP TABLE table_name; Например, команда: DROP TABLE city; удалит старый справочник городов. При наличии ограничений целостности в данной таблице в виде внешних ключей, данная команда не будет выполнена, поскольку у таблицы city есть подчиненные записи в таблице client. Для правильного выполнения команды надо вначале изменить констранты (внешние ключи) в подчиненной таблице – на новую таблицу, после чего выполнять команду DROP. Пример. alter table client drop constraint <имя констранта>; alter table client add constraint <новое имя констранта> foreign key (N_CITY) references city (N_CITY); Задание: после формирования нового справочника городов, удалите старый. Указания. Как посмотреть имена констрантов, определенных для таблицы CLIENT select t.constraint_name, t.constraint_type, t.r_constraint_name from all_constraints t where t.table_name = 'CLIENT' constraint_type – тип констранта, С (check), P (первичный ключ), R ( внешний ключ ) r_constraint_name – констрант, куда ссылается таблица ALTER TABLE Изменить некоторые свойства таблицы можно с помощью команд ALTER TABLE. Переименование таблицы: ALTER TABLE table_name RENAME TO new_table_name; Добавление полей: ALTER TABLE table_name ADD (column_1 column-definition, column_2 column-definition, ... column_n column_definition ); Здесь column-definition – тип данных с указанием длины поля. Пример: ALTER TABLE client ADD n_mobile_phone number(20); Удаление полей: ALTER TABLE table_name DROP COLUMN column_name; Изменение полей: ALTER TABLE table_name MODIFY (column_1 column_type_1 null/not null, column_2 column_type_2 null/not null, ... column_n column_type_n null/not null ); Эта команда приводит поле column_x к типу column_name_x. Если был указан модификатор null, то после изменения поле не может содержать NULL-значений. Задание: изменить имя нового справочника городов в CITY, чтобы соответствовать написанным ранее запросам. Создание последовательностей. Последовательность значений можно создать командой CREATE SEQUENCE. Формат вызова: CREATE SEQUENCE sequence_name MINVALUE value MAXVALUE value START WITH value INCREMENT BY value CACHE value; Названия полей не требуют комментариев. Если хотите начать последовательность с какого-нибудь конкретного значения, надо изменить значение START WITH (по умолчанию START WTH = MINVALUE). Задание: Только что созданная таблица не имеет счетчика для первичного ключа, т.ч. любые DML-операции с ней приведут к рассогласованию данных. В последствии будет изучен механизм триггеров для формирования первичного ключа, однако он будет использовать последовательность. Создайте последовательность для новой таблицы. Начать последовательность с числа, на единицу большего самого большого значения поля n_street (первичного ключа). Лабораторная работа 8. Элементы PL/SQL. Процедуры, функции, триггеры. Конструкции PL/SQL позволяют выполнять сложную обработку данных и администрировать базу данных: выполнять автоматический аудит изменений, выполнять задания по времени, изменять данные таблиц и пр. Любая из рассматриваемых здесь конструкций состоит из четырех секций, формирующих блок PL/SQL: Секция заголовка (header) Секция объявлений (declaration), необязательная Выполняемая секция (execution) Секция исключений (exception), необязательная Заголовок процедуры, функции или триггера содержит спецификацию этой процедуры, функции или триггера (описание входных параметров и возвращаемого значения). В секции объявлений перечисляются локальные переменные, используемые в процедуре, функции или триггере. Область видимости локальной переменной – блок PL/SQL. Структура выполняемой секции: BEGIN executable_section [EXCEPTION exception_section] END Изучение секции исключений не входит в данный курс и выносится на самостоятельное изучение. Объявление переменных имеет следующий синтаксис: DECLARE variable_name variable_type; variable_type это обычно один из трех типов: Number, Date, Varchar2 (числа, даты и строки). Например: City varchar2(100); (вторым параметром указывается размерность строки) В секции объявлений процедуры или функции ключевое слово DECLARE не употребляется. Хранимые процедуры предназначены для выполнения сложных действий над данными и не имеют возвращаемых параметров. Создание хранимой процедуры осуществляется оператором CREATE PROCEDURE. Синтаксис: CREATE [OR REPLACE] PROCEDURE procedure_name [ (parameter [,parameter]) ] IS [declaration_section] BEGIN executable_section [EXCEPTION exception_section] END [procedure_name]; parameter ::= parameter_name IN | OUT | IN OUT parameter_type; IN – Параметр может быть использован в процедуре или функции. Его значение не может быть изменено в теле процедуры или функции. OUT – Параметр не может быть использован в процедуре или функции. Его значение может быть изменено в теле процедуры или функции. IN OUT – Параметр может быть использован в процедуре или функции. Его значение может быть изменено в теле процедуры или функции. Пример: CREATE OR REPLACE PROCEDURE set_payment_value IS hot_cost number; cold_cost number; BEGIN select n_tariff_cold into cold_cost from tariff where d_tariff=(select max(d_tariff) from tariff); select n_tariff_hot into hot_cost from tariff where d_tariff=(select max(d_tariff) from tariff); update computation set n_pay = n_difference_hot * hot_cost + n_difference_cold * cold_cost where n_pay is null; END; Для того чтобы сохранить какое-нибудь значение, полученное в результате запроса используется конструкция select into, например: select n_tariff_cold, n_tariff_hot into cold_cost, hot_cost from tariff where d_tariff=(select max(d_tariff) from tariff); При этом нельзя поместить в переменную за раз больше одного значения. Например, в указанном примере, если есть несколько разных тарифов с одной максимальной датой, то запрос вернет несколько строк и сгенерируется исключение (ошибка при попытке сохранить несколько значений в переменную). Аналогично, если в таблице tariff еще не заведено ни одного тарифа запрос вернет 0 строк и сгенерируется исключение (не найдено значений которые можно сохранить в переменную) set_payment_value обрабатывает ситуацию, когда в таблицу начислений внесены новые данные о показателях счетчиков и вычислена разница между старыми показателями и новыми, но стоимость израсходованной воды еще не вычислена. Процедура set_payment_value как раз и вычисляет стоимость израсходованной воды по последнему тарифу. Задания: 1. Создать процедуру для вычисления разницы новых и старых показаний. 2. Создать процедуру для вычисления долга. 3. Создать процедуру для вычисления суммы «к оплате». Хранимые функции – это хранимые процедуры, возвращающие одно значение параметра определенного типа. Создать хранимую процедуру можно оператором CREATE FUNCTION. Синтаксис: CREATE [OR REPLACE] FUNCTION function_name [ (parameter [,parameter]) ] RETURN return_datatype IS | AS [declaration_section] BEGIN executable_section [EXCEPTION exception_section] END [function_name]; Чтобы вернуть значение функции, надо объявить переменную типа return_datatype в секции объявлений. Сам возврат осуществляется командой RETURN function_value; где function_value – объявленная переменная. Задание: Написать функции, принимающие один параметр – дату, и вычисляющие самый последний тариф (соотв. на холодную и горячую воду), дата принятия которого не позднее указанного значения. Триггер – это особый вид хранимых процедур. Триггер привязан к конкретной таблице и совершается только тогда, когда совершается какое-либо DML – действие над таблицей (update, insert or delete). Триггер позволяет совершить какие-либо действия над обновляемыми столбцами, либо в других таблицах для обеспечения семантической целостности структуры таблиц. Например, триггеры служат для вставки значений первичных ключей при insert-командах. Создать триггер можно оператором CREATE TRIGGER. Синтаксис: CREATE [OR REPLACE] TRIGGER trigger_name trigger_moment trigger_event ON table_name [ FOR EACH ROW ] DECLARE variable_declarations BEGIN trigger_body [EXCEPTION exception_handling] END; trigger_moment – момент срабатывания триггера. Определяет, когда будет срабатывать триггер: до (BEFORE) или после (AFTER) наступления триггерного события (выполнения запускающего оператора). Если указано значение BEFORE, триггер выполняется до каких-либо проверок ограничений на строки, затрагиваемые триггерным событием. Никакие строки не блокируются. Если выбрать ключевое слово AFTER, то триггер будет срабатывать после того, как запускающий оператор завершит свою работу, и будут выполнены проверки всех ограничений. В этом случае затрагиваемые строки блокируются на время выполнения триггера. trigger_event – триггерное событие. Может принимать значение INSERT, UPDATE, DELETE или их комбинацию через OR. Определяет, какой оператор должен быть применен к таблице для срабатывания триггера. Если присутствует ключевая фраза FOR EACH ROW, то триггер выполнится для каждой строки таблицы. Если нет, то триггер сработает только один раз. Пример: create or replace trigger "BI_STREET" before insert on "STREET" for each row begin select "STREET_SEQ".nextval into :NEW.N_STREET from dual; end; Этот триггер срабатывает до вставки следующей записи в таблицу и заносит в поле n_street следующее значение последовательности street_seq, формируя первичный ключ для вставляемой строки. «For each row» означает, что при вставке нескольких строк, триггер выполнится для каждой строки. Для обращения к значениям полей новой, добавляемой записи используется префикс :NEW. Аналогично для обращения к значениям полей старой записи (в случае триггера на update или delete) используется префикс :OLD Задания: 1. Для нового справочника городов создать триггер на вставку (формирование первичного ключа).