Подзапросы в основных командах SQL.
Подзапросы в SELECT
В выражении SELECT мы можем вводить подзапросы четырьмя способами:
- В условии в выражении WHERE
- В условии в выражении HAVING
- В качестве таблицы для выборки в выражении FROM
- В качестве спецификации столбца в выражении SELECT
Рассмотрим некоторые из этих случаев. Например, получим все товары, у которых цена выше средней:
12 | SELECT * FROM Products WHERE Price > ( SELECT AVG (Price) FROM Products) |
Чтобы получить нужные товары, нам вначале надо выполнить подзапрос на получение средней цены товара: SELECT AVG(Price) FROM Products
.
Оператор IN
Нередко подзапросы применяются вместе с оператором IN, который выбирает из набора значений. И подзапрос как раз может предоставить требуемый набор значений. Например, выберем все товары из таблицы Products, на которые есть заказы в таблице Orders:
12 | SELECT * FROM Products WHERE Id IN ( SELECT ProductId FROM Orders) |
То есть подзапрос в данном случае выбирает все идентификаторы товаров из Orders, затем по этим идентификаторам извлекаютя товары из Products.
Добавив оператор NOT, мы можем выбрать те товары, на которые нет заказов в таблице Orders:
12 | SELECT * FROM Products WHERE Id NOT IN ( SELECT ProductId FROM Orders) |
Стоит отметить, что это не самый эффективный способ для извлечения связанных данных из других таблиц, так как для сведения данных из разных таблиц можно использовать оператор JOIN, который рассматривается в следующей главе.
Получение набора значений
При использовании в операторах сравнения подзапросы должны возвращать одно скалярное значение. Но иногда возникает необходимость получить набор значений. Чтобы при использовании в операторах сравнения подзапрос мог возвращать набор значений, перед ним необходимо использовать один из операторов: ALL, SOME или ANY.
При использовании ключевого слова ALL условие в операции сравнения должно быть верно для всех значений, которые возвращаются подзапросом. Например, найдем все товары, цена которых меньше чем у любого товара фирмы Apple:
12 | SELECT * FROM Products WHERE Price < ALL ( SELECT Price FROM Products WHERE Manufacturer= 'Apple' ) |
Если бы мы в данном случае опустили бы ключевое слово ALL, то мы бы столкнулись с ошибкой.
Допустим, если данный подзапрос возвращает значения vаl1, val2 и val3, то условие фильтрации фактически было бы аналогично объединению этих значений через оператор AND:
1 | WHERE Price < val1 AND Price < val2 AND Price < val3 |
В тоже время подобный запрос гораздо проще переписать другим образом:
12 | SELECT * FROM Products WHERE Price < ( SELECT MIN (Price) FROM Products WHERE Manufacturer= 'Apple' ) |
Как работает оператор ALL:
x > ALL (1, 2)
эквивалентноx > 2
x < ALL (1, 2)
эквивалентноx < 1
x = ALL (1, 2)
эквивалентно(x = 1) AND (x = 2)
x <> ALL (1, 2)
эквивалентноx NOT IN (1, 2)
Операторы ANY и SOME условие в операции сравнения должно быть истинным для хотя бы одного из значений, возвращаемых подзапросом. По своему действию оба этих оператора аналогичны, поэтому можно применять любой из них. Например, в следующем случае получим товары, которые стоят меньше самого дорогого товара компании Apple:
12 | SELECT * FROM Products WHERE Price < ANY ( SELECT Price FROM Products WHERE Manufacturer= 'Apple' ) |
И также стоит отметить, что данный запрос можно сделать проще, переписав следующим образом:
12 | SELECT * FROM Products WHERE Price < ( SELECT MAX (Price) FROM Products WHERE Manufacturer= 'Apple' ) |
Как работает оператор ANY (а также SOME):
x > ANY (1, 2)
эквивалентноx > 1
x < ANY (1, 2)
эквивалентноx < 2
x = ANY (1, 2)
эквивалентноx IN (1, 2)
x <> ANY (1, 2)
эквивалентно(x <> 1) OR (x <> 2)
Подзапрос как спецификация столбца
Результат подзапроса может представлять отдельный столбец в выборке. Например, выберем все заказы и добавим к ним информацию о названии товара:
123 | SELECT *, ( SELECT ProductName FROM Products WHERE Id=Orders.ProductId) AS Product FROM Orders |
Подзапросы в команде INSERT
В команде INSERT подзапросы могут применяться для определения значения, которое вставляется в один из столбцов:
12345678 | INSERT INTO Orders (ProductId, CreatedAt, ProductCount, Price) VALUES ( ( SELECT Id FROM Products WHERE ProductName= 'Galaxy S8' ), '2018-05-23' , 2, ( SELECT Price FROM Products WHERE ProductName= 'Galaxy S8' ) ) |
Подзапросы в команде UPDATE
В команде UPDATE подзапросы могут применяться:
- В качестве устанавливаемого значения после оператора SET
- Как часть условия в выражении WHERE
Так, увеличим в таблице Orders количество купленных товаров компании Apple на 2:
123 | UPDATE Orders SET ProductCount = ProductCount + 2 WHERE ProductId IN ( SELECT Id FROM Products WHERE Manufacturer= 'Apple' ); |
Или установим для заказа цену товара, полученную в результате подзапроса:
123 | UPDATE Orders SET Price = ( SELECT Price FROM Products WHERE Id=Orders.ProductId) + 3000 WHERE Id=1; |
Подзапросы в команде DELETE
В команде DELETE подзапросы также применяются как часть условия. Так, удалим все заказы на Galaxy S8:
12 | DELETE FROM Orders WHERE ProductId=( SELECT Id FROM Products WHERE ProductName= 'Galaxy S8' ); |