SELECT
Подзапросы чаще всего используются с инструкцией SELECT. При этом используется следующий синтаксис
SELECT имя_столбца FROM имя_таблицы WHERE часть условия IN
(SELECT имя_столбца FROM имя_таблицы WHERE часть условия IN
(SELECT имя_столбца FROM имя_таблицы WHERE условие)
...
)
;
Ниже представлена струтура таблицы для демонстрации примеров
snum | sname | city | comm |
---|---|---|---|
1 | Колованов | Москва | 10 |
2 | Петров | Тверь | 25 |
3 | Плотников | Москва | 22 |
4 | Кучеров | Санкт-Петербург | 28 |
5 | Малкин | Санкт-Петербург | 18 |
6 | Шипачев | Челябинск | 30 |
7 | Мозякин | Одинцово | 25 |
8 | Проворов | Москва | 25 |
cnum | cname | city | rating | snum |
---|---|---|---|---|
1 | Деснов | Москва | 90 | 6 |
2 | Краснов | Москва | 95 | 7 |
3 | Кириллов | Тверь | 96 | 3 |
4 | Ермолаев | Обнинск | 98 | 3 |
5 | Колесников | Серпухов | 98 | 5 |
6 | Пушкин | Челябинск | 90 | 4 |
7 | Белый | Одинцово | 85 | 1 |
8 | Чудинов | Москва | 89 | 3 |
9 | Проворов | Москва | 95 | 2 |
10 | Лосев | Одинцово | 75 | 8 |
onum | amt | odate(YEAR) | cnum | snum |
---|---|---|---|---|
1001 | 420 | 2013 | 9 | 4 |
1002 | 653 | 2005 | 10 | 7 |
1003 | 960 | 2016 | 2 | 1 |
1004 | 320 | 2016 | 3 | 3 |
1005 | 200 | 2015 | 5 | 4 |
1006 | 2560 | 2014 | 5 | 4 |
1007 | 1200 | 2013 | 7 | 1 |
1008 | 50 | 2017 | 1 | 3 |
1009 | 564 | 2012 | 3 | 7 |
1010 | 900 | 2018 | 6 | 8 |
Вывести суммы заказов и даты, которые проводил продавец с фамилией "Плотников".
Начнем с такого примера и для начала вспомним, как бы делали этот запрос ранее: посмотрели бы в таблицу SALES
(или выполнили отдельный запрос), определили бы snum
продавца "Плотников" — он равен 3. И выполнили бы запрос SQL с помощью условия WHERE
.
SELECT amt, odate
FROM orders
WHERE snum = 3
amt | odate |
---|---|
320 | 2016 |
50 | 2017 |
Такой запрос, очевидно, не очень универсален, если нам захочется выбрать тоже самое для другого продавца, то всегда придется определять его snum
. В SQL предусмотрена возможность объединять такие запросы в один путем превращения одного из них в подзапрос (вложенный запрос).
SELECT amt, odate
FROM orders
WHERE snum = ( SELECT snum
FROM sales
WHERE sname = 'Плотников')
В этом примере мы определяем с помощью вложенного запроса идентификатор snum
по фамилии из таблицы SALES
, а затем, в таблице ORDERS
определяем по этому идентификатору нужные нам значения.
Показать уникальные номера и фамилии продавцов, которые провели сделки в 2016 году.
SELECT snum, sname
FROM sales
WHERE snum IN ( SELECT snum
FROM orders
WHERE odate = 2016)
Этот SQL запрос отличается тем, что вместо знака = здесь используется оператор IN.
Оператор IN
следует использовать в том случае, если вложенный подзапрос SQL возвращает несколько значений.
То есть в запросе происходит проверка, содержится ли идентификатор snum
из таблицы SALES
в массиве значений, который вернул вложенный запрос. Если содержится, то SQL выдаст фамилию этого продавца.
snum | sname |
---|---|
1 | Колованов |
3 | Плотников |
Предыдущие примеры, которые мы уже рассмотрели, сравнивали в условии WHERE
одно поле. Это конечно хорошо, но стоит отметить, что в SQL предусмотрена возможность сравнения сразу нескольких полей, то есть можно использовать вложенный запрос с несколькими параметрами.
Вывести пары покупателей и продавцов, которые осуществили сделку между собой, но не позднее 2014 года
Запрос чем то похож на предыдущий, только теперь мы добавляем еще одно поле для сравнения.
SELECT cname as 'Покупатель', sname as 'Продавец'
FROM customers cus, sales sal
WHERE (cus.cnum, sal.snum) IN ( SELECT cnum, snum
FROM orders
WHERE odate < 2014 )
Покупатель | Продавец |
---|---|
Проворов | Кучеров |
Лосев | Мозякин |
Белый | Колованов |
Кириллов | Мозякин |
В этом примере мы сравниваем сразу два поля одновременно по идентификаторам. То есть из таблицы ORDERS
берутся те строки, которые удовлетворяют условию не позднее 2014 года, затем вместо идентификаторов подставляются значение имен покупателей и продавцов.
На самом деле, такой запрос SQL используется крайне редко, обычно используют оператор INNER JOIN.
Оператор as
нужен для того, чтобы при выводе SQL показывал не имена полей, а то, что мы зададим. И после оператора FROM
за именами таблиц стоят сокращения, которые потом используются — это псевдонимы. Псевдонимы можно называть любыми именами, в этом запросе они используются для явного определения поля, так как мы несколько раз обращаемся к одному и тому же полю, только из разных таблиц.
Подзапросы могут использоваться с инструкциямиSELECT
,INSERT
,UPDATE
иDELETE
вместе с операторами типа=
,<
,>
,>=
,<=
,IN
,BETWEEN
и т.д.
Далее будут показы примеры использования вложеных запросов с использованием базы данныхworld
. БД находится в папке_lec\7\db
вместе с лекцией.
CREATE
Данный пример несовсем относится к теме занятия, но по жизни он очень может пригодиться.
Задача - создать копию существующей таблицы.
Копия существующей таблицы может быть создана с помощью комбинации CREATE TABLE
и SELECT
.
Новая таблица будет имеет те же определение столбцов, могут быть выбраны все столбцы или отдельные столбцы. При создании новой таблицы с помощью существующей таблицы, новая таблица будет заполняться с использованием существующих значений в старой таблице.
CREATE TABLE NEW_TABLE_NAME AS
SELECT [ column1, column2...columnN ]
FROM EXISTING_TABLE_NAME
[ WHERE ]
Создадим копию таблицы city
. Вопрос - почему 1=0?
CREATE TABLE city_bkp AS
SELECT *
FROM city
WHERE 1=0
INSERT
Задача - создать копию существующей таблицы.
Подзапросы также могут использоваться с инструкцией INSERT
. Инструкция INSERT
использует данные, возвращаемые из подзапроса, для вставки в другую таблицу. Выбранные в подзапросе данные могут быть изменены. Основной синтаксис следующий.
INSERT INTO table_name [ (column1 [, column2 ]) ]
SELECT [ *|column1 [, column2 ]
FROM table1 [, table2 ]
[ WHERE VALUE OPERATOR ]
Копирование всей таблицы полностью
INSERT INTO city_bkp SELECT * FROM city
Копируем города которые находся в стране с численостью не меньше 500тыс.человек, но не больше 1 миллиона.
INSERT INTO city_bkp
SELECT * FROM city
WHERE CountryCode IN
(SELECT Code FROM country
WHERE Population < 1000000 AND Population > 500000)
UPDATE
Подзапрос может использоваться в сочетании с инструкцией UPDATE
. Один или несколько столбцов в таблице могут быть обновлены при использовании подзапроса с помощью инструкции UPDATE
. Основной синтаксис следующий.
UPDATE table
SET column_name = new_value
[ WHERE OPERATOR [ VALUE ]
(SELECT COLUMN_NAME
FROM TABLE_NAME)
[ WHERE) ]
Исходя из того, что у нас есть таблица CITY_BKP
, которая является резервной копией таблицы CITY
, в следующем примере для всех записей, для которых Population
больше или равно 100000, применяет коэффициент 0,25.
UPDATE city_bkp SET Population = Population * 0.25
WHERE Population IN (
SELECT Population FROM city
WHERE Population >= 100000 )
DELETE
Подзапрос может использоваться в сочетании с инструкцией DELETE
, так же как и со всеми описанными выше инструкциями. Основной синтаксис следующий.
DELETE FROM TABLE_NAME
[ WHERE OPERATOR [ VALUE ]
(SELECT COLUMN_NAME
FROM TABLE_NAME)
[ WHERE) ]