 
        
        Автор (id, фамилия, имя, телефон, адрес)
authors(au_id, au_fname, au_lname, phone, address, city, country)
Издательство (номер, название издательства, город, страна)
publishers(pub_id, pub_name, city, country)
Книги (id книги, название, жанр (только 1), id издательства, число страниц, стоимость, кол-во проданных книг, дата публикации)
titles (title_id, title_name, type, pub_id, pages, price, sales, pubdate)
Авторы книг (id книги, id автора, порядок автора (с 1))
title_authors (title_id, au_id, au_order)
Подзапросы
Ранее были рассмотрены единичные команды SELECT для работы с одной или несколькими таблицами. В данной лекции будут рассмотрены запросы разных уровней, которые позволяют считывать или изменять данные на основании результатов другого запроса.
Подзапрос – это команда SELECT, встроенная в другую команду SQL. Подзапрос может быть расположен в:
1) предложении SELECT, FROM, WHERE или HAVING другой команды SELECT
2) другом подзапросе
3) команде INSERT, UPDATE или DELETE.
Структура подзапросов такая же, как структура обычной команды SELECT. Отличия:
1) можно поместить подзапрос в предложение SELECT, FROM, WHERE, HAVING или в другой запрос;
2) подзапрос всегда должен заключаться в круглые скобки;
3) нельзя подзапрос точкой с запятой (точкой с запятой необходимо завершить команду, которая включает подзапрос);
4) подзапрос включает одну команду SELECT;
5) подзапрос может использовать столбцы в таблицах, которые приводятся в предложении FROM самого подзапроса или другого подзапроса;
6) если таблица появляется во внутреннем, а не во внешнем запросе, не получится включить столбцы этой таблицы в конечный результат (то есть в предложение SELECT внешнего запроса).
Чаще всего работа происходит с подзапросами в предложении WHERE, которые принимают одну из следующих форм:
- WHERE test_expr op (subquery);
- WHERE test_expr [NOT] IN (subquery);
- WHERE test_expr op ALL (subquery);
- WHERE test_expr op ANY (subquery);
- WHERE [NOT] EXISTS (subquery).
test_expr является буквенным значением, названием столбца, выражением или запросом;
op – это оператор сравнения (=, <>, <, <=, > или >=);
subquery – простой или сложный запрос.
Также можно использовать их в предложении HAVING.
Многие запросы могут быть преобразованы в соединения. Запрос – это лишь способ сгруппировать одну таблицу с другой, не создавая при этом соединения. Поскольку создавать и исполнять подзапросы иногда затруднительно, можно предпочесть им соединения. Однако некоторые задачи можно решить только с помощью подзапросов. Как правило, нет никакой разницы между командой, которая использует подзапрос, и ее эквивалентом, который использует соединение (но бывают и исключения).
На представленные ниже запросы приведены эквивалентные команды, которые используют подзапросы и соединения.
Запрос с использованием в условии оператора IN:
SELECT *
FROM table1
WHERE id IN
(SELECT id FROM table2);
И внутреннее соединение:
SELECT table1.*
FROM table1
INNER JOIN table2
ON table1.id = table2.id;
Следующие три команды тоже эквивалентны (подзапрос NOT IN):
SELECT *
FROM table1
WHERE id NOT IN
(SELECT id FROM table2);
(подзапрос NOT EXISTS):
SELECT table1.*
FROM table1
WHERE NOT EXISTS
(SELECT id FROM table2);
и (внешнее соединение)
SELECT table1.*
FROM table1
LEFT OUTER JOIN table2
ON table1.id = table2.id
WHERE table2.id IS NULL;
Оператор in
Оператор IN рассматривался при рассмотрении предложения WHERE, чтобы сравнивать значение, значение в столбце или выражение со списком значений. Также можно использовать запрос, чтобы создать список.
Параметры при проверке на принадлежность значения множеству, представленному подзапросом:
1) IN работает со значениями в результате запроса так же, как со списком значений;
2) запрос может быть простым или сложным;
3) список столбцов команды SELECT запроса может включать только одно выражение или название столбца;
4) сравниваемые значения должны относиться к одному типу данных или быть конвертируемыми;
5) запрос должен считать одно значение (результат одной строки или столбца). Запрос, который считывает несколько значений, приводит к ошибке.
Проверка на вхождение значения во множество
В предложении WHERE команды SELECT:
WHERE test_expr [NOT] IN (subquery)
test_expr – это буквенное значение, название столбца, выражение или запрос, который возвращает значение;
subquery – запрос, который считывает один столбец и любое количество строк.
Если значение test_expr равно любому значению, полученному с помощью запроса, условие IN задается как истинное.
Условие IN задается как ложное, если результат запроса пустой, ни одна строка
в результате запроса не соответствует test_expr или если все значения в результате запроса равны NULL. Чтобы инвертировать результат условия, укажите NOT.
Предложение HAVING имеет такую же структуру:
HAVING test_expr [NOT] IN (subquery).
Примеры:
1) Отобразить список всех издательств, которые опубликовали биографии.
SELECT pub_name
FROM publishers
WHERE pub_id IN
(SELECT pub_id
FROM titles
WHERE type = 'biography');
2) Отобразить список соавторов, которые живут в Калифорнии и получают менее 50% гонорара за книгу.
SELECT au_id, au_fname, au_lname
FROM authors
WHERE state = 'CA'
AND au_id IN
(SELECT au_id
FROM title_authors
WHERE royalty_share < 0.5
AND au_order > 1);
Оператор IN эквивалентен ключевому слову ANY.
Оператор NOT IN эквивалентен выражению <> ALL (не <> ANY).
