Подзапросы в основных командах SQL.

Подзапросы в SELECT
В выражении SELECT мы можем вводить подзапросы четырьмя способами:
- В условии в выражении WHERE
- В условии в выражении HAVING
- В качестве таблицы для выборки в выражении FROM
- В качестве спецификации столбца в выражении SELECT
Рассмотрим некоторые из этих случаев. Например, получим все товары, у которых цена выше средней:
| 12 | SELECT* FROMProductsWHEREPrice > (SELECTAVG(Price) FROMProducts) |
Чтобы получить нужные товары, нам вначале надо выполнить подзапрос на получение средней цены товара: SELECT AVG(Price) FROM Products.
Оператор IN
Нередко подзапросы применяются вместе с оператором IN, который выбирает из набора значений. И подзапрос как раз может предоставить требуемый набор значений. Например, выберем все товары из таблицы Products, на которые есть заказы в таблице Orders:
| 12 | SELECT* FROMProductsWHEREId IN(SELECTProductId FROMOrders) |
То есть подзапрос в данном случае выбирает все идентификаторы товаров из Orders, затем по этим идентификаторам извлекаютя товары из Products.
Добавив оператор NOT, мы можем выбрать те товары, на которые нет заказов в таблице Orders:
| 12 | SELECT* FROMProductsWHEREId NOTIN(SELECTProductId FROMOrders) |
Стоит отметить, что это не самый эффективный способ для извлечения связанных данных из других таблиц, так как для сведения данных из разных таблиц можно использовать оператор JOIN, который рассматривается в следующей главе.
Получение набора значений
При использовании в операторах сравнения подзапросы должны возвращать одно скалярное значение. Но иногда возникает необходимость получить набор значений. Чтобы при использовании в операторах сравнения подзапрос мог возвращать набор значений, перед ним необходимо использовать один из операторов: ALL, SOME или ANY.
При использовании ключевого слова ALL условие в операции сравнения должно быть верно для всех значений, которые возвращаются подзапросом. Например, найдем все товары, цена которых меньше чем у любого товара фирмы Apple:
| 12 | SELECT* FROMProductsWHEREPrice < ALL(SELECTPrice FROMProducts WHEREManufacturer='Apple') |
Если бы мы в данном случае опустили бы ключевое слово ALL, то мы бы столкнулись с ошибкой.
Допустим, если данный подзапрос возвращает значения vаl1, val2 и val3, то условие фильтрации фактически было бы аналогично объединению этих значений через оператор AND:
| 1 | WHEREPrice < val1 ANDPrice < val2 ANDPrice < val3 |
В тоже время подобный запрос гораздо проще переписать другим образом:
| 12 | SELECT* FROMProductsWHEREPrice < (SELECTMIN(Price) FROMProducts WHEREManufacturer='Apple') |
Как работает оператор ALL:
x > ALL (1, 2)эквивалентноx > 2x < ALL (1, 2)эквивалентноx < 1x = ALL (1, 2)эквивалентно(x = 1) AND (x = 2)x <> ALL (1, 2)эквивалентноx NOT IN (1, 2)
Операторы ANY и SOME условие в операции сравнения должно быть истинным для хотя бы одного из значений, возвращаемых подзапросом. По своему действию оба этих оператора аналогичны, поэтому можно применять любой из них. Например, в следующем случае получим товары, которые стоят меньше самого дорогого товара компании Apple:
| 12 | SELECT* FROMProductsWHEREPrice < ANY(SELECTPrice FROMProducts WHEREManufacturer='Apple') |
И также стоит отметить, что данный запрос можно сделать проще, переписав следующим образом:
| 12 | SELECT* FROMProductsWHEREPrice < (SELECTMAX(Price) FROMProducts WHEREManufacturer='Apple') |
Как работает оператор ANY (а также SOME):
x > ANY (1, 2)эквивалентноx > 1x < ANY (1, 2)эквивалентноx < 2x = ANY (1, 2)эквивалентноx IN (1, 2)x <> ANY (1, 2)эквивалентно(x <> 1) OR (x <> 2)
Подзапрос как спецификация столбца
Результат подзапроса может представлять отдельный столбец в выборке. Например, выберем все заказы и добавим к ним информацию о названии товара:
| 123 | SELECT*, (SELECTProductName FROMProducts WHEREId=Orders.ProductId) ASProduct FROMOrders |

Подзапросы в команде INSERT
В команде INSERT подзапросы могут применяться для определения значения, которое вставляется в один из столбцов:
| 12345678 | INSERTINTOOrders (ProductId, CreatedAt, ProductCount, Price)VALUES( (SELECTId FROMProducts WHEREProductName='Galaxy S8'), '2018-05-23', 2, (SELECTPrice FROMProducts WHEREProductName='Galaxy S8')) |
Подзапросы в команде UPDATE
В команде UPDATE подзапросы могут применяться:
- В качестве устанавливаемого значения после оператора SET
- Как часть условия в выражении WHERE
Так, увеличим в таблице Orders количество купленных товаров компании Apple на 2:
| 123 | UPDATEOrdersSETProductCount = ProductCount + 2WHEREProductId IN(SELECTId FROMProducts WHEREManufacturer='Apple'); |
Или установим для заказа цену товара, полученную в результате подзапроса:
| 123 | UPDATEOrdersSETPrice = (SELECTPrice FROMProducts WHEREId=Orders.ProductId) + 3000WHEREId=1; |
Подзапросы в команде DELETE
В команде DELETE подзапросы также применяются как часть условия. Так, удалим все заказы на Galaxy S8:
| 12 | DELETEFROMOrdersWHEREProductId=(SELECTId FROMProducts WHEREProductName='Galaxy S8'); |



