Практическое занятие № 5

Тема: Использование подзапросов для выборки данных

Цель работы: получить практические навыки по выборке данных из нескольких таблиц с использованием подзапросов

 

Ход работы

 

Пусть имеется БД "dbase" в формате SQL Server Данная БД состоит из 6 таблиц со следующей структурой:

 

Таблицы связаны так:

 

Главная таблица Подчиненная таблица Поле для связи Тип связи
otdelen spec id_otd 1 : ∞
spec grupy id_spec 1 : ∞
grupy students id_grup 1 : ∞
students ocenki id_stud 1 : ∞
predmety ocenki id_predmet 1 : ∞

 

 

Выполните подключение БД к серверу (если она отсутствует).

 

Указания: разархивируйте архив.

Запустите утилиту "Microsoft SQL Server Management Studio", пройдите регистрацию введя информацию: Параметры подлинности = "Проверка подлинности SQL Server", Имя пользователя=sa, пароль=111 (у Вас может быть свой пароль).

В дереве объектов вызовите контекстное меню папки "Базы данных" и выберите команду "Присоединить". В правой части появится окно, в котором с помощью кнопки "Добавить" укажите файл из архива и щелкните ОК.

В результате у вас на сервере будет зарегистрирована новая БД.

Для создания запроса выберите в левой части нужную БД и щелкните на кнопке "Создать запрос"   В правой части окна введите текст запроса.

 

 Для выполнения запроса щелкните на кнопке "Выполнить" . В нижней части окна отобразится набор отобранных данных.

 

Подзапросы в разделе From

 

Запрос 1. Определите средний балл для каждого студента. Отсортировать по среднему по убыванию и по фамилии по возрастанию.

 

Запрос 2. Определите размер стипендии для каждого студента по формуле (1475 руб. - средний балл = 5; 1300 руб. - средний балл >4; 0 в остальных случаях). Отсортировать по стипендии по убыванию и по фамилии по возрастанию.

 

Запрос 3. Определите суммарную стипендию для каждой группы учебного заведения.

 

Запрос 4. Определите среднюю стипендию для каждой специальности.

 

Запрос 5. Определите суммарную стипендию отдельно для парней и девушек.

 

Запрос 6. Отобрать группы, сумма стипендии в которых выше 10000.

 

Подзапросы в разделе Where

 

Запрос 7. Выведите самых старших студентов (с наименьшей датой рождения).

 

Запрос 8. Выведите студентов, которые родились в те же дни, что и студенты группы 38.

 

Запрос 9. Выведите студентов, которые родились в любые дни, кроме тех, в которые родились студенты группы 38.

 

Запрос 10. Выведите студентов, которые не имеют троек (хорошисты и отличники).

 

Запрос 11. Определите, сколько хорошистов и отличников в каждой группе.

 

Запрос 12. Вывести группы, в которых количество хорошистов и отличников превышает 10 человек.

 

Запрос 13. Для каждого отделения определите количество девушек троечниц.

 

Подзапросы, на существование

 

Запрос 14. Вывести список групп, в которых нет троечников.

 

Запрос 15. Вывести список групп, в которых есть троечники.

 

Запрос 16. Вывести список групп, в которых учатся студенты с именем Ярослав.

 

Отбор по расчетным показателям

 

Запрос 17. Отобрать список студентов, у которых средний балл выше среднего балла по учебному заведению

 

Запрос 18. Отобрать список студентов, у которых средний балл выше, чем средний балл в их группе

 

Выполнение работы

Запрос 1.

 

Указания:

Вначале напишем подзапрос, который по таблице ocenki определяет для каждого id_stud его средний балл.

 

select id_stud,

       avg(ocenka) as srbal

from ocenki

group by id_stud;

 

Если этот запрос рассмотреть как таблицу и связать его с таблицей students по полю id_stud, то можно решить поставленную задачу:

 

select fam,

       imya,

       srbal

from students inner join (select id_stud,

                                 avg(ocenka) as srbal

                          from ocenki

                          group by id_stud) as a

on students.id_stud=a.id_stud

order by srbal desc, fam;

 

Запрос 2.

 

Указания:

Вначале напишем подзапрос, который по таблице ocenki определяет для каждого id_stud его средний балл.

 

select id_stud,

       avg(ocenka) as srbal

from ocenki

group by id_stud;

 

Если этот запрос рассмотреть как таблицу и связать его с таблицей students по полю id_stud, то можно решить поставленную задачу:

 

select fam,

       imya,

       case when srbal=5 then 1475

       when srbal>=4 then 1300

       else 0 end as stip

from students inner join (select id_stud,

                                 avg(ocenka) as srbal

                          from ocenki

                          group by id_stud) as a

on students.id_stud=a.id_stud

order by stip desc, fam;

 

Запрос 3.

 

Указания:

В предыдущий запрос внесем изменения: для отбора названия группы добавим таблицу grupy с указанием ее связи с таблицей students, по полю stip рассчитываем сумму, выполним группировку по полю nazv_grup

 

select nazv_grup,

       sum(case when srbal=5 then 1475

                when srbal>=4 then 1300

                else 0 end) as sumstip

from grupy inner join students on grupy.id_grup=students.id_grup

           inner join (select id_stud,

                              avg(ocenka) as srbal

                       from ocenki

                       group by id_stud) as a

           on students.id_stud=a.id_stud

group by nazv_grup;

 

Запрос 4.

 

Указания:

Изменим предыдущий запрос: для отбора специальности добавим поле nazv_spec и таблицу spec с указанием связи с таблицей grupy, заменим функцию sum на avg, выполним группировку по полю nazv_spec

 

select nazv_spec,

       avg(case when srbal=5 then 1475

                when srbal>=4 then 1300

                else 0 end) as sredstip

from spec inner join grupy on spec.id_spec=grupy.id_spec

          inner join students on grupy.id_grup=students.id_grup

          inner join (select id_stud,

                             avg(ocenka) as srbal

                      from ocenki

                      group by id_stud) as a

          on students.id_stud=a.id_stud

group by nazv_spec;

 

Запрос 5.

 

Указания:

Запрос проще, чем предыдущие. Отберем pol из таблицы students и суммарную стипендию (как в запросе № 2). Свяжем таблицу students и подзапрос расчета среднего балла по полю id_stud и выполним группировку по полю pol.

 

select pol,

       avg(case when srbal=5 then 1475

                when srbal>=4 then 1300

                else 0 end) as sredstip

from students inner join (select id_stud,

                                 avg(ocenka) as srbal

                          from ocenki

                          group by id_stud) as a

on students.id_stud=a.id_stud

group by pol;

 

Запрос 6.

 

Указания:

Для выполнения расчета полностью походит текст запроса № 2. Только для отбора нужно добавить в раздел Having условие 'формула для суммы стипендии'>10000

 

select nazv_grup,

       sum(case when srbal=5 then 1475

                when srbal>=4 then 1300

                else 0 end) as sumstip

from grupy inner join students on grupy.id_grup=students.id_grup

           inner join (select id_stud,

                              avg(ocenka) as srbal

                       from ocenki

                       group by id_stud) as a

           on students.id_stud=a.id_stud

group by nazv_grup

having sum(case when srbal=5 then 1475

                when srbal>=4 then 1300

                else 0 end) >10000;

 

Запрос 7.

 

Указания:

Сначала напишем подзапрос нахождения минимальной даты рождения по таблице students

 

select min(datar)

from students;

 

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

 

select *

from students

where datar = (select min(datar)

               from students);

 

Запрос 8.

 

Указания:

Сначала напишем подзапрос для отбора дат рождения всех студентов из группы 38. Название группы находится в поле nazv_grup из таблицы grupy. Свяжем эту таблицу с таблицей students.

 

select datar

from grupy inner join students on grupy.id_grup=students.id_grup

where nazv_grup like '38%';

 

Теперь отберем студентов у которых дата рождения равна одной из дат, отобранных выше.

 

select *

from students

where datar in (select datar

                from grupy inner join students on grupy.id_grup=students.id_grup

                where nazv_grup like '38%');

 

Запрос 9.

 

Указания:

Для решения будем использовать предыдущий запрос, только перед функцией in добавим отрицание not.

 

select *

from students

where datar not in (select datar

                from grupy inner join students on grupy.id_grup=students.id_grup

                where nazv_grup like '38%');

 

Запрос 10.

 

Указания:

Для решения напишем подзапрос, который отбирает оценки конкретного студента (например, id_stud=1).

 

В данном решении подзапрос будет использоваться в условии Where.

 

select ocenka

from ocenki

where id_stud=1;

 

Теперь выведем студентов, не имеющих среди своих оценок 3. Для получения оценок очередного студента будем передавать id_stud из главного запроса в подзапрос

 

select *

from students

where 3 not in (select ocenka

                from ocenki

                where ocenki.id_stud=students.id_stud);

 

Запрос 11.

 

Указания:

Для решения внесем изменения в предыдущий запрос.

Для вывода названия группы будем использовать поле nazv_grup из таблицы grupy, которую свяжем с таблицей students. Количество студентов будем считать с помощью функции count(students.id_stud) и группировать данные по полю nazv_grup.

Нам нужны только те записи, у которых среди отобранных оценок нет 3.

 

select nazv_grup,

       count(students.id_stud) as kolstud

from grupy inner join students on grupy.id_grup=students.id_grup

           where 3 not in (select ocenka

                           from ocenki

                           where id_stud=students.id_stud)

group by nazv_grup;

 

Запрос 12.

 

Указания:

Запрос создается на основе предыдущего запроса, но с добавлением условия в разделе Having, в котором значение функции count(students.id_stud) > 10

 

select nazv_grup,

       count(students.id_stud) as kolstud

from grupy inner join students on grupy.id_grup=students.id_grup

           where 3 not in (select ocenka

                           from ocenki

                           where id_stud=students.id_stud)

group by nazv_grup

having count(students.id_stud)>10;

 

Запрос 13.

 

Указания:

В предыдущий запрос добавим поле nazv_otd из таблицы otdelen  и укажем цепочку связей таблиц otdelen, spec, grupy, students. Добавим условие по полю pol (женский), и сгруппируем данные по полю nazv_otd.

 

select nazv_otd,

       count(students.id_stud) as kol_stud

from otdelen inner join spec on otdelen.id_otd=spec.id_otd

             inner join grupy on spec.id_spec=grupy.id_spec

             inner join students on grupy.id_grup=students.id_grup

where 3 in (select ocenka

            from ocenki

            where id_stud=students.id_stud)

and pol='ж'

group by nazv_otd;

 

Запрос 14.

 

Указания:

Создадим подзапрос, который из таблицы students для конкретной группы (например,  id_grup=1) отбирает список троечников

 

select *

from students

where id_grup=1

      and 3 in (select ocenka

                from ocenki

                where id_stud=students.id_stud);

 

Используя подзапрос выберем названия групп, которые не имеют троечников. Для отображения названия группы будем использовать поле nazv_grup из таблицы grupy. Значение id_grup каждой группы из главного запроса последовательно подставим в условие подчиненного запроса.

Отбираем группы, для которых не существует студентов с тройками (функция not exists).

 

select nazv_grup

from grupy

where not exists

    (select *

     from students

     where id_grup=grupy.id_grup

     and 3 in (select ocenka

                     from ocenki

                     where id_stud=students.id_stud));

 

Запрос 15.

 

Указания:

Перепишем предыдущий запрос, но отберем группы, у которых СУЩЕСТВУЮТ троечники (функция exists).

 

select nazv_grup

from grupy

where exists

    (select *

     from students

     where id_grup=grupy.id_grup

     and 3 in (select ocenka

                     from ocenki

                     where id_stud=students.id_stud));

 

Запрос 16.

 

Указания:

Вначале напишем подзапрос, в котором для отдельной группы (например, id_grup=1) отберем из таблицы students данные студентов с именем Ярослав.

 

select *

from students

where imya='Ярослав' and id_grup=1;

 

Для отображения названия группы будем использовать поле nazv_grup из таблицы grupy. Значение id_grup каждой группы из главного запроса последовательно подставим в условие подчиненного запроса.

Отбираем группы, в которых имеются Ярославы (функция exists).

 

select nazv_grup

from grupy

where exists

    (select *

     from students

     where imya='Ярослав' and id_grup=grupy.id_grup);

 

Запрос 17.

 

Указания:

Создадим подзапрос расчета среднего балла по учебному заведению:

 

select avg(ocenka)

from ocenki

 

Создадим подзапрос нахождения среднего балла для каждого id_stud в таблице ocenki.

 

select id_stud,

       avg(ocenka) as srbal

from ocenki

group by id_stud

 

Для решения задачи свяжем таблицу students и второй подзапрос по полю id_stud. При этом в условии отбора where будем использовать значение среднего балла по учебному заведению из первого подзапроса.

 

select fam,

       imya,

       srbal

from students inner join (select id_stud,

                                 avg(ocenka) as srbal

                          from ocenki

                          group by id_stud) as a

               on students.id_stud=a.id_stud

where srbal>(select avg(ocenka)

             from ocenki)

order by fam, imya

 

Запрос 18.

 

Указания:

Создадим подзапрос расчета среднего балла по конкретной группе (например, id_grup=1):

 

select avg(ocenka)

from students inner join ocenki

              on students.id_stud=ocenki.id_stud

where students.id_grup=1

 

Используя подзапрос выведем список студентов со средним баллом выше среднего в их группе.

Подзапрос будем использовать в условии отбора where. При этом номер группы из таблицы students главного запроса будет сравниваться с полем id_grup из таблицы students подзапроса. Для устранения неопределенности присвоим этим таблицам имена s1 и s2.

 

select fam,

       imya,

       srbal

from students as s1 inner join (select id_stud,

                                avg(ocenka) as srbal

                          from ocenki

                          group by id_stud) as a

              on s1.id_stud=a.id_stud

where srbal>(select avg(ocenka)

             from students as s2 inner join ocenki

             on s2.id_stud=ocenki.id_stud

             where s2.id_grup=s1.id_grup);

 

Скачайте исходную БД в формате MySQL.  Выполните все рассмотренные выше запросы в этой СУБД.

 

Указания: распакуйте архив. В архиве находится файл со скриптом БД.

 

Запустите утилиту EMS SQL Manager for MySQL. В правой части окна программы выберите команду "Выполнить SQL скрипт". В новом окне выберите команду "Выполнить скрипт из файла". В диалоговом окне укажите распакованный файл скрипта. Если появится окно регистрации, то укажите Пользовать=root, Пароль=111. Если такого окна не появилось, то нажимайте в окне ОК. Появится сообщение, что скрипт выполнен успешно и появится окно для регистрации БД. Перенесите ее в правую часть окна и нажмите ОК. В результате БД будет установлена, зарегистрирована и готова к работе.

В левой части окна можете открыть БД, просмотреть ее таблицы.

 

Для выполнения запросов в окне выполните команду "Инструменты - Показать редактор SQL"В результате в правой части окна откроется поле для ввода тестов запросов.

 

Скачайте исходную БД в формате SQLite.  Выполните все рассмотренные выше запросы в этой СУБД.

 

Указания: распакуйте. В архиве находится файл БД.

 

Запустите утилиту SQLIte Expert Pro. На панели инструментов щелкните на кнопке "Open Database" (вторая слева) и в диалоге открытия файла укажите распакованный файл БД. После подключения должен отобразится значок БД.

В правой части окна перейдите на закладку "SQL"В верхней части вводите текст запроса и нажимайте на кнопку "Execute SQL"Если в запросе нет ошибок, то в нижней части будет отображаться результат отбора.

 

Замечание. В SQLite для тестовых полей не работает операция "=", только функция like. Следовательно, в запросе № 17 условие по полю imya запишите так:

 

imya like 'Ярослав%'