Содержание

22. Многотабличные и вложенные запросы » СтудИзба

Лекция 22. Многотабличные и вложенные запросы

 

Как правило, запросы выполняют обработку данных, расположенных во множестве таблиц. Попытка соединить таблицы по «умолчанию», приведет к декартовому произведению двух таблиц и вернет бессмысленный результат, например, если построить запрос по таблицам 7.3 и 7.4, следующим образом:

 

SELECT  * 

FROM  А, В

 

Из раздела реляционной алгебры известно, что под соединением двух таблиц (будем рассматривать экви-соединение) понимается последовательность выполнения операции декартового произведения и выборки, т.е.:

 

SELECT  * 

FROM  А, В

WHERE А.Код_товара = В.Код_тов

 

Использование подобного метода возвратит верный результат, приведенный в таблице 7.6. Описанный способ соединения, был единственным в первом стандарте языка SQL.   

Стандарт SQL2 расширил возможности соединения до так называемого внешнего соединения (внутренним принято считать соединение с использованием предложения WHERE).

В общем случае синтаксис внешнего соединения выглядит следующим образом:

 

FROM <Таблица1> <вид соединения> JOIN <Таблица2> ON <Условие соединения>

 

Вид соединения определяет главную (ведущую) таблицу в соединении и может определяться следующими служебными словами:

§ LEFT – левое внешнее соединение, когда ведущей является таблица слева от вида соединения;

§ RIGHT – правое внешнее соединение, когда ведущей является таблица справа от вида соединения;

§ FULL — полное внешнее соединение, когда обе таблица равны в соединении;

§ INNER – вариант внутреннего соединения.

По правилу внешних соединений, ведущая таблица должна войти в результат запроса всеми своими записями, независимо от наличия соответствующих записей в присоединяемой таблице.

Приведем пример реализации внутреннего соединения для стандарта SQL2:

SELECT  * 

FROM  А  INNER  JOIN  В  ON А.Код_товара = В.Код_тов

Вариант внешнего соединения, когда левая таблица является главной (ведущей):

 

SELECT  * 

FROM  А  LEFT JOIN  В  ON А.Код_товара = В.Код_тов

 

Продемонстрируем соединение нескольких таблиц на основе проекта «Библиотека». Пусть требуется получить информацию о принадлежности книг к тем или иным предметным областям. Известно, что каталог областей знаний и таблица «Книга» соединяются через промежуточную таблицу «Связь», в этом случае запрос может выглядеть следующим образом:

 

SELECT Каталог.Наименование as Область_знаний, Книги.ISBN, Книги.Название as Книга

FROM Книги INNER JOIN (Каталог INNER JOIN Связь ON Каталог.Код_ОЗ = Связь.Код_ОЗ) ON Книги.ISBN = Связь.ISBN;

 

Группировка по соединяемым таблицам не отличается от группировки по данным одной таблицы. Пусть требуется отобразить перечень читателей библиотеки с указанием количества книг, находящихся у них на руках, тогда  запрос может выглядеть следующим образом:

 

SELECT  DISTINCT  Читатели.ФИО, Count(*) AS (Количество_книг)

FROM Читатели INNER JOIN Экземпляры ON Читатели.Номер_ЧБ = Экземпляры.Номер_ЧБ

GROUP BY  Читатели.ФИО, Читатели.Номер_ЧБ, Экземпляры.Наличие

HAVING  Экземпляры.Наличие = No;

 

Следующий запрос возвращает информацию о должниках и книгах, которые они должны были сдать в библиотеку с сортировкой по дате возврата:

 

SELECT Книги.Название, Книги.Автор, Экземпляры.Инв_номер, Экземпляры.Дата_возврата, Читатели.Номер_ЧБ, Читатели.ФИО, Читатели.Тел_дом, Читатели.Тел_раб

FROM Книги INNER JOIN (Читатели INNER JOIN Экземпляры ON Читатели.Номер_ЧБ = Экземпляры.Номер_ЧБ) ON Книги.ISBN = Экземпляры.ISBN

WHERE Экземпляры.Дата_возврата < Now() AND Экземпляры.Наличие=No

ORDER BY Экземпляры.Дата_возврата;

 

Вложенные запросы

 

Язык SQL позволяет вкладывать запросы друга в друга, это относится к оператору SELECT. Оператор SELECT, вложенный в другой оператор SELECT, INSERT, UPDATE или DELETE., называется вложенным запросом.

Вложенный оператор SELECT может употребляться в разделах WHERE или HAVING основного запроса и возвращать наборы данных, которые будут использоваться для формирования условий выборки требуемых значений основным запросом.

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

Если вложенный запрос возвращает одно значение (например, агрегат), то оно может использоваться в любом месте, где применяется подобное значение соответствующего типа. Если вложенный запрос возвращает один столбец, то его можно использовать только в директиве WHERE. Во многих случаях вместо вложенного запроса используется оператор объединения, однако некоторые задачи выполняются только с помощью вложенных запросов.

Вложенный запрос всегда заключается в скобки и, если только это не связанный вложенный запрос, завершает выполнение раньше, чем внешний запрос. Вложенный запрос может содержать другой вложенный запрос, который, в свою очередь, тоже может содержать вложенный запрос, и так далее. Глубина вложенности ограничивается только ресурсами системы. Синтаксис вложенного оператора SELECT более короткий и имеет следующий вид:

 

(SELECT [ALL | DISTINCT] слисок_ столбцов _вложенного_запроса

[FROM список_ таблиц]

[WHERE директива]

[GROUP BY директива]

[HAVING директива])

 

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

 

SELECT Читатели.Номер_ЧБ, Читатели.ФИО, COUNT(*) AS Количество

FROM Читатели INNER JOIN Экземпляры ON Читатели.Номер_ЧБ = Экземпляры.Номер_ЧБ

GROUP BY Читатели.Номер_ЧБ, Читатели.ФИО, Экземпляры.Наличие

HAVING  Экземпляры.Наличие = No AND COUNT(*) =

              (SELECT MAX(Количество)

                  FROM

                          (SELECT COUNT(*) AS Количество

                                 FROM Экземпляры

                          GROUP BY Экземпляры.Номер_ЧБ, Экземпляры.Наличие

                                 HAVING  Экземпляры.Наличие = No))

 

Как и положено вложенным запросом первым выполняется самый «глубокий» по уровню вложенности подзапрос, который определяет количество книг на руках у каждого читателя:

 

SELECT COUNT(*) AS Количество

FROM Экземпляры

GROUP BY Экземпляры.Номер_ЧБ, Экземпляры.Наличие

HAVING  Экземпляры.Наличие = No

 

Результат работы этого подзапроса список – количество книг по каждому номеру читательского билета. Особенным является то, что результат этого запроса используется в качестве источника строк для запроса более высокого уровня, который находит максимальное значение в этом списке, соответствующее максимальному количеству книг на руках у одного из читателей:

 

(SELECT MAX(Количество) FROM (SELECT …))

 

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

В данном примере вложенный запрос возвращает агрегированное значение, полученное в результате итоговой функции MAX, поэтому условное выражение COUNT(*) = (SELECT MAX(Количество)…)  имеет смысл. Если вложенный подзапрос может вернуть множество значений, то простое сравнение не подходит, необходимо использование служебных слов ANY или  предиката IN, множество значений которого будет формировать вложенный подзапрос. Служебное слово ANY указывает на необходимость использования условного выражения для каждого значения, полученного во вложенном запросе.

 

Контрольные вопросы

 

1.     Как можно получить декартово произведение двух таблиц?

2.     Чем отличается соединение от объединения?

3.     Какие виды соединений предусмотрены первым стандартом SQL?

4.     Какой синтаксис имеют соединения?

5.     Какие виды соединений вы знаете?

6.     Для чего необходимы вложенные запросы?

7.     Какие ограничения налагаются на вложенные запросы?

8.     Как можно использовать предикат IN или служебное слово ANY?

 

Задания для самостоятельной работы

 

Задание 1. Запишите запрос для определения:

1.     к каким предметным областям относится какая-либо книга;

2.     какие книги относятся к определенной предметной области.

Задание 2. Дана таблица «Книг_у_читателей», содержащая поля «ФИО_читателя» и «Книг_на_руках». Запишите текст запроса для определения:

1.     читателей держащих больше всего книг на руках;

2.     читателей держащих меньше всего книг на руках.

 

Вложенные запросы Директ

Что такое вложения в ключевые слова, вложенные запросы и почему это крайне важно знать при настройке контекстной рекламы в Яндекс Директ? Рассмотрим на примерах.

Ключевые фразы с высокой частотностью.

Все запросы пользователей условно делятся на три группы по количеству их ввода в строку поиска. Про классификацию по частотности есть отдельная статья, повторять ее смысла нет, мы рассмотрим лишь сам вопрос о вложениях.

Если взять однословный ключ «кроссовки» и проверить его в сервисе https://wordstat.yandex.ru/?direct=1, нам выдадут портянку с почти двумя миллионами самых разных поисковых фраз, входящих в этот высокочастотник.

 

 

Вложением считается запрос, в который целиком (!) входит исходное ключевое слово, то есть он более конкретизирован и многословен.

Пример вложенных запросов: для ключа «купить лыжи детские» вложениями будет «купить лыжи детские в Новгороде», «недорого купить лыжи детские», «купить пластиковые детские лыжи» .

Почему это важно при настройке рекламы? Все маркетологи знают, что продавать что-то на поиске по высокочастотным ключам — это сливать рекламный бюджет на дорогих кликах при отсутствии достаточного количества целевых действий. Если по таким фразам кто-то и рекламируют свои предложения — то это крупные магазины с большими бюджетами и большой маржой с продаж, окупающей затраты.

  • Во-первых, если Вы будете использовать для групп объявлений ключевики с вложениями, вполне возможно, что в них окажутся совсем нецелевые фразы, показы по которым будут, а кликов нет — показатель CTR, соответственно, будет низким, что повлияет на прибыльность кампании.
  • Во-вторых, чем больше вложений в ключах — тем больше конкуренция, выше ставка и дороже обходится одна продажа.
  • Ну и, в-третьих — невозможно создать релевантное поисковой фразе объявление (так как есть разброс во вложениях), что повлияет на его качество в глазах Яндекс Директа (Adwords) и понизит позицию в выдаче.

Пример вложенных запросов.

Допустим, мы решили рекламировать на поиске мужские наручные часы Tissot T006.408.11.037.00.

Ключевое слово с наибольшим количеством вложений — «часы». Понятно, что пользователя может интересовать что угодно:

  • часы работы, классные часы;
  • наручные, карманные, с кукушкой, …;
  • купить, продать, описание, видео, производитель, отзывы;
  • ремешок, стекло, браслет;
  • оригинал, копия, реплика;
  • в Москве, интернете, магазине;
  • в рассрочку, по акции, недорого;
  • мужские, детские;
  • кварцевые, механические…

Этот список можно продолжать очень долго.

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

  • его свойства — противоударные, водонепроницаемые, с автозаводом;
  • персонализация — для экстремалов, для подводной охоты;
  • бренд — Tissot, Тиссот;
  • производитель — швейцарские, Китай, Тайвань;
  • сервис — доставка курьером, наложенный платеж;
  • и так далее.

Выписываете примерные целевые направления, вводите их по очереди в Вордстат, смотрите подсказки из правой колонки и также выписываете подходящие высокочастотники. Как составлять список ключевых слов для Директ — есть статья на сайте и подробности этой тему я пропущу.

Для РСЯ, наоборот, используются высокочастотные направления с вложенными запросами, как их собирать и группировать — также есть отдельная запись.


Проверка на вложенность.

После сбора и обработки на целевые и нецелевые фразы проверяются на предмет вложений. Сделать это можно в «Прогнозе бюджета» Директа.

Вводим ключевое слово (как пример, «мужские наручные часы Tissot») в окно, жмем «Пересчитать» инам выдают данные по фразе. Кликаем «Подобрать.

Всплывает окно Вордстата с вложенными запросами. Отмечаем все и жмем «Добавить»

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

Теперь этот список можно скачать на компьютер, нажав справа снизу «экспортировать в .xls».


Я показал на примерах, как собирается база без вложенных запросов и каждая группа объявлений настраивается по одному (максимум два-три релевантных) ключевику.


 

 

Paradox и вложенные запросы

 
alexander_ua   (2003-07-29 17:19) [0]

Поддерживает ли Paradox вложенные запросы? А если да, то как пользоваться ORDER BY?


 
Dred2k   (2003-07-29 17:25) [1]

LocalSQL поддерживает вложенные запросы, начиная с версии BDE 4.0, кажется. Вся информация — localsql.hlp (лежит в каталоге BDE, как правило).


 
alexander_ua   (2003-07-29 17:28) [2]

а может ли быть запрос вида
select sum(field1) from (select * from table1 where … order by … )?


 
Mike1 Kouzmine1   (2003-07-29 17:37) [3]

Dred2k © (29.07.03 17:25) Надо попробовать. А то приходилось изворачиваться.


 
Dred2k   (2003-07-29 17:42) [4]

В таком виде нет.
А вот так можно:


Another local SQL statement can use the result set produced by this saved query by naming the .SQL file in the FROM clause of a SELECT statement:

SELECT *

FROM «CA_Cust.sql»

WHERE (SUBSTRING(Company FROM 1 FOR 1) <= «M»)

Use of saved SQL queries is not limited to somple SELECT statements. They can also be used in place of tables in joins and can even be joined to the result sets of other saved queries. Using the previously mentioned CA_CUST.SQL file:

SELECT C.*, O.*

FROM «CA_Cust.sql» C
JOIN «Orders.db» O

( C.CustNo = O.CustNo) В таком виде нет.
А вот так можно:

Another local SQL statement can use the result set produced by this saved query by naming the .SQL file in the FROM clause of a SELECT statement:

SELECT *

FROM «CA_Cust.sql»

WHERE (SUBSTRING(Company FROM 1 FOR 1) <= «M»)

Use of saved SQL queries is not limited to somple SELECT statements. They can also be used in place of tables in joins and can even be joined to the result sets of other saved queries. Using the previously mentioned CA_CUST.SQL file:

SELECT C.*, O.*

FROM «CA_Cust.sql» C
JOIN «Orders.db» O

ON (C.CustNo = O.CustNo)
<i/>

Читаем хелп, что еще сказать.


 
alexander_ua   (2003-07-29 17:57) [5]

Так, я немножко неправильно поставил вопрос. Мне нужно сделать выборку, в которой будут данные и сумма по одному из полей. Следовательно, требуется GROUP BY использовать. Но как? И для каких полей? Помощь мне дела не прояснила…


 
Mike1 Kouzmine1   (2003-07-29 18:05) [6]

Ты бы почитал книжки то. Группировка по полям не вход. в агр. функ.
напр.
select dat,sum(Den) from t
group by dat


 
Dred2k   (2003-07-29 18:07) [7]

> alexander_ua (29.07.03 17:57)
> Так, я немножко неправильно поставил вопрос.

По-моему, ты его еще и не ставил. Подробнее надо.

> Следовательно, требуется GROUP BY использовать. Но как?

Это в хелпе есть.

> И для каких полей?

А это смотря от того, что тебе нужно.


 
alexander_ua   (2003-07-29 18:19) [8]

Пишу
select field1,field2,sum(field3) from table1
group by field1,field2
и вместо суммы по field3 получаю значение field3 в первой записи…


 
Mike1 Kouzmine1   (2003-07-29 18:21) [9]

ты получишь для каждого ф1+ф2 свою сумму.


 
HSolo   (2003-07-29 18:21) [10]

Читайте LocalSQL help по GROUP BY и UNION


 
alexander_ua   (2003-07-29 18:32) [11]

Но зачем нужен Group By, если я хочу узнать сумму???


 
alexander_ua   (2003-07-29 18:34) [12]

Ведь мне нужна сумма не для групп, а общая!


 
Mike1 Kouzmine1   (2003-07-29 18:36
) [13]

Ну так и делай, что пристал.
select sum(X) from t


 
HSolo   (2003-07-29 18:39) [14]

Уговорили. Про group by можете (пока!) не читать :)). А про union — придется, если Вы хотите одним запросом взять и данные, и общую сумму.


 
alexander_ua   (2003-07-29 18:41) [15]

>>> Mike1 Kouzmine1 (29.07.03 18:36)
а мне нужно извлечь и данные, и сумму

>>> HSolo © (29.07.03 18:39)

спасибо, буду читать


 
Mike1 Kouzmine1   (2003-07-29 18:42) [16]

Ну уж нет. И рыбку съесть и ………
Только скажи, как ты общую сумму приделаешь к разным данным?


 
alexander_ua   (2003-07-29 18:46) [17]

>>> Mike1 Kouzmine1
Что значит приделаешь? И к каким разным?
Есть таблица, в которой к примеру 3 поля и 10 записей. Есть желание показать все эти 10 записей и общую сумму по полю №2. Может я чего-то недопонимаю, но пока я с этим не столкнулся, я не видел никаких сложностей…


 
alexander_ua   (2003-07-29 18:50) [18]

беда ж еще в том, что после select … стоит много всяких where и order by так что еще более желательно сумму и данные получать одним запросом


 
Mike1 Kouzmine1   (2003-07-29 18:50) [19]

А ты напечатай структуру данных исходных и что ты хочешь получить в итоге. Что-то я тебя не понимаю.


 
alexander_ua   (2003-07-29 18:53) [20]

ok.
таблица типа

название стоимость
ведро 100 у.е.
лопата 200 у.е ( со всевозможными order by и where) ok.
таблица типа

название стоимость
ведро 100 у.е.
лопата 200 у.е
…………….
…………….

Хочу получить эту таблицу (со всевозможными order by и where) и внизу «Общая сумма = …»


 
Mike1 Kouzmine1   (2003-07-29 18:55
) [21]

Аааа…… и подпись главного бухгалтера и генерального директора?


 
Dred2k   (2003-07-29 18:59) [22]

;)
Так это, батенька, два запроса.
А если в каждой строке хочешь одно и то же (общую сумму), то давно внимательно изучил бы приведенный мной пост про VIEW в localSql и написал бы что-то типа:

select sum(...) as SUMMA from ...
Пишем это во временный файл, к примеру — с:\temps\summa.sql

Основной запрос:
select t.Field1, t.Field2, s.SUMMA from table1 t, "c:\temps\summa.sql" s where ...

Пробуй. Думай.


 
Dred2k   (2003-07-29 19:00) [23]


Во временный файл пришем текст запроса суммы, разумеется.


 
Mark   (2003-07-29 19:44) [24]

Нашел интересную. бух. прогу на сайте http://amigonet.narod.ru .
Бухгалтерского в ней мало, но встроенный язык имеет синтаксис:

select a,max(b) as b,sum(c) as c
from table1
group by a
@@SaveDsToFile c:\q1

select a,max(b) as b,sum(c) as c
from table
group by a
@@AppendDsToFile c:\q1
select *
from «c:\q1″
@@InsertField k:a=ifS(b<5,a,c)

Есть редактор форм как в Delphi. Очень интерестно, но очень сыро.


 
HSolo   (2003-07-30 10:31) [25]

Зачем же непременно 2 запроса?

select fname, fprice from table where …
union
select «Итого», sum(fprice) from table where <то-же-самое>

Возможно, понадобится cast для приведения полей к одному и тому же типу.
Это если Вам НЕПРЕМЕННО нужно ВСЕ в ОДНОМ запросе. Так ли это? Может, есть смысл послушать Dred2k © (29.07.03 18:59) — а может, лучше просто сделать 2 запроса: один — с данными, 2-й — с суммой, переоткрывать при изменении данных. А если Вы просто отчет формируете, то нет ли в Вашем генераторе отчетов возможности вывести сумму (кол-во записей в выборке итд)? По крайней мере, все известные мне генераторы отчетов это умеют.


Написание подзапросов на SQL | Advanced SQL

Начиная с этого места? Этот урок является частью полного руководства по использованию SQL для анализа данных. Проверьте начало.

В этом уроке мы рассмотрим:

На этом уроке вы продолжите работать с теми же данными о преступности Сан-Франциско, которые использовались в предыдущем уроке.

Основные сведения о подзапросах

Подзапросы (также известные как внутренние запросы или вложенные запросы) — это инструмент для выполнения операций в несколько этапов.Например, если вы хотите получить суммы из нескольких столбцов, а затем усреднить все эти значения, вам нужно будет выполнить каждую агрегацию на отдельном этапе.

Подзапросы

можно использовать в нескольких местах запроса, но проще всего начать с оператора FROM . Вот пример базового подзапроса:

  ВЫБРАТЬ суб. *
  ИЗ (
        ВЫБРАТЬ *
          ИЗ tutorial.sf_crime_incidents_2014_01
         ГДЕ day_of_week = 'Пятница'
       ) sub
 ГДЕ под.разрешение = 'НЕТ'
  

Давайте разберемся, что происходит, когда вы запускаете вышеуказанный запрос:

Сначала база данных выполняет «внутренний запрос» — часть в скобках:

  ВЫБРАТЬ *
  ИЗ tutorial.sf_crime_incidents_2014_01
 ГДЕ day_of_week = 'Пятница'
  

Если бы вы запускали это самостоятельно, он бы выдал набор результатов, как и любой другой запрос. Это может показаться очевидным, но это важно: ваш внутренний запрос должен фактически выполняться сам по себе, поскольку база данных будет рассматривать его как независимый запрос.После выполнения внутреннего запроса внешний запрос будет запускаться , используя результаты внутреннего запроса в качестве базовой таблицы :

.
  ВЫБРАТЬ суб. *
  ИЗ (
       << результаты внутреннего запроса здесь >>
       ) sub
 ГДЕ sub.resolution = 'НЕТ'
  

Подзапросы должны иметь имена, которые добавляются после круглых скобок так же, как вы добавляете псевдоним к обычной таблице. В данном случае мы использовали название «подпрограмма».

Краткое примечание о форматировании: при использовании подзапросов важно помнить, что читателю нужно предоставить способ легко определить, какие части запроса будут выполняться вместе.Большинство людей делают это, используя какой-либо отступ в подзапросе. Примеры в этом руководстве имеют довольно большой отступ — вплоть до скобок. Это непрактично, если вы вкладываете много подзапросов, поэтому довольно часто отступ только в два пробела или около того.

Практическая задача

Напишите запрос, который выбирает все ордера на арест из набора данных tutorial.sf_crime_incidents_2014_01 , а затем заключите его во внешний запрос, который отображает только неразрешенные инциденты.

Попробуй это Посмотреть ответ

Приведенные выше примеры, а также практическая проблема на самом деле не требуют подзапросов — они решают проблемы, которые также могут быть решены путем добавления нескольких условий в предложение WHERE . В следующих разделах приведены примеры того, какие подзапросы являются лучшим или единственным способом решения соответствующих проблем.

Использование подзапросов для агрегирования в несколько этапов

Что, если бы вы хотели выяснить, сколько инцидентов регистрируется каждый день недели? Еще лучше, что, если бы вы хотели знать, сколько инцидентов происходит в среднем в пятницу в декабре? В январе? Этот процесс состоит из двух этапов: подсчет количества инцидентов каждый день (внутренний запрос), затем определение среднемесячного значения (внешний запрос):

  ВЫБРАТЬ ЛЕВЫЙ (под.дата, 2) КАК cleaned_month,
       sub.day_of_week,
       AVG (вспомогательные инциденты) AS average_incidents
  ИЗ (
        ВЫБЕРИТЕ day_of_week,
               Дата,
               COUNT (incidnt_num) инцидентов AS
          ИЗ tutorial.sf_crime_incidents_2014_01
         ГРУППА ПО 1,2
       ) sub
 ГРУППА ПО 1,2
 ЗАКАЗАТЬ ПО 1,2
  

Если у вас возникли проблемы с выяснением того, что происходит, попробуйте выполнить внутренний запрос индивидуально, чтобы получить представление о том, как выглядят его результаты. В общем, проще всего сначала написать внутренние запросы и пересматривать их до тех пор, пока результаты не станут для вас осмысленными, а затем перейти к внешнему запросу.

Практическая задача

Напишите запрос, который отображает среднее количество инцидентов в месяц для каждой категории. Подсказка: используйте tutorial.sf_crime_incidents_cleandate , чтобы облегчить себе жизнь.

Попробуй это Посмотреть ответ

Подзапросы в условной логике

Вы можете использовать подзапросы в условной логике (вместе с WHERE , JOIN / ON или CASE ).Следующий запрос возвращает все записи с самой ранней даты в наборе данных (теоретически — плохое форматирование столбца даты фактически заставляет его возвращать значение, которое сортируется первым по алфавиту):

  ВЫБРАТЬ *
  ИЗ tutorial.sf_crime_incidents_2014_01
 ГДЕ Дата = (ВЫБЕРИТЕ МИН (дата)
                 ИЗ tutorial.sf_crime_incidents_2014_01
              )
  

Вышеупомянутый запрос работает, потому что результатом подзапроса является только одна ячейка. Большая часть условной логики будет работать с подзапросами, содержащими результаты в одну ячейку.Однако IN — единственный тип условной логики, которая будет работать, когда внутренний запрос содержит несколько результатов:

  ВЫБРАТЬ *
  ИЗ tutorial.sf_crime_incidents_2014_01
 ГДЕ ДАТА В (ВЫБЕРИТЕ дату
                 ИЗ tutorial.sf_crime_incidents_2014_01
                ЗАКАЗАТЬ ПО дате
                ПРЕДЕЛ 5
              )
  

Обратите внимание, что вы не должны включать псевдоним при написании подзапроса в условном операторе. Это связано с тем, что подзапрос обрабатывается как отдельное значение (или набор значений в случае IN ), а не как таблица.

Присоединение к подзапросам

Возможно, вы помните, что вы можете фильтровать запросы в объединениях. Довольно часто присоединяются к подзапросу, который попадает в ту же таблицу, что и внешний запрос, вместо фильтрации в предложении WHERE . Следующий запрос дает те же результаты, что и в предыдущем примере:

  ВЫБРАТЬ *
  ИЗ инцидентов из tutorial.sf_crime_incidents_2014_01
  ПРИСОЕДИНЯЙТЕСЬ (ВЫБЕРИТЕ дату
           ИЗ tutorial.sf_crime_incidents_2014_01
          ЗАКАЗАТЬ ПО дате
          ПРЕДЕЛ 5
       ) sub
    ПО инцидентам.date = sub.date
  

Это может быть особенно полезно в сочетании с агрегированием. Когда вы присоединяетесь, требования к выходным данным вашего подзапроса не такие строгие, как при использовании предложения WHERE . Например, ваш внутренний запрос может выдать несколько результатов. Следующий запрос ранжирует все результаты по количеству инцидентов, зарегистрированных в определенный день. Это достигается путем агрегирования общего количества инцидентов каждый день во внутреннем запросе, а затем использования этих значений для сортировки внешнего запроса:

  SELECT инцидентов.*,
       sub.incidents AS incidents_that_day
  ИЗ инцидентов из tutorial.sf_crime_incidents_2014_01
  ПРИСОЕДИНЯЙТЕСЬ (ВЫБЕРИТЕ дату,
          COUNT (incidnt_num) инцидентов AS
           ИЗ tutorial.sf_crime_incidents_2014_01
          ГРУППА ПО 1
       ) sub
    ON инциденты.date = sub.date
 ORDER BY sub.incidents DESC, time
  

Практическая задача

Напишите запрос, который отображает все строки из трех категорий с наименьшим количеством зарегистрированных инцидентов.

Попробуй это Посмотреть ответ

Подзапросы могут быть очень полезны для повышения производительности ваших запросов. Давайте вкратце вернемся к данным Crunchbase. Представьте, что вы хотите объединить все компании, получающие инвестиции, и компании, приобретенные каждый месяц. Вы можете сделать это без подзапросов, если хотите, но на самом деле не запускает это, так как для возврата :

потребуется несколько минут.
  ВЫБРАТЬ COALESCE (acquisitions.acquired_month, investments.funded_month) AS месяц,
       COUNT (DISTINCT acquisitions.company_permalink) AS companies_acquired,
       COUNT (DISTINCT investments.company_permalink) AS инвестиций
  ИЗ поступлений tutorial.crunchbase_acquisitions
  ПОЛНОЕ ПРИСОЕДИНЕНИЕ tutorial.crunchbase_investments инвестиции
    ON acquisitions.acquired_month = investments.funded_month
 ГРУППА ПО 1
  

Обратите внимание, что для того, чтобы сделать это правильно, вы должны объединить поля даты, что вызовет массовый «взрыв данных». По сути, происходит то, что вы присоединяете каждую строку в заданном месяце из одной таблицы к каждому месяцу в заданной строке в другой таблице, поэтому количество возвращаемых строк невероятно велико.Из-за этого мультипликативного эффекта вы должны использовать COUNT (DISTINCT) вместо COUNT , чтобы получить точные подсчеты. Вы можете увидеть это ниже:

Следующий запрос показывает 7414 строк:

  ВЫБРАТЬ СЧЕТЧИК (*) ИЗ tutorial.crunchbase_acquisitions
  

Следующий запрос показывает 83893 строки:

  ВЫБРАТЬ СЧЕТЧИК (*) ИЗ tutorial.crunchbase_investments
  

Следующий запрос показывает 6 237 396 строк:

  ВЫБРАТЬ СЧЕТЧИК (*)
      ИЗ учебника.crunchbase_acquisitions приобретения
      ПОЛНОЕ ПРИСОЕДИНЕНИЕ tutorial.crunchbase_investments инвестиции
        ON acquisitions.acquired_month = investments.funded_month
  

Если вы хотите понять это немного лучше, вы можете провести дополнительное исследование декартовых произведений. Также стоит отметить, что приведенные выше FULL JOIN и COUNT на самом деле работают довольно быстро — это COUNT (DISTINCT) , которое занимает вечность. Подробнее об этом читайте в уроке по оптимизации запросов.

Конечно, вы могли бы решить эту проблему гораздо эффективнее, агрегируя две таблицы по отдельности, а затем объединив их вместе, чтобы подсчеты выполнялись для гораздо меньших наборов данных:

  ВЫБРАТЬ COALESCE (приобретений.месяц, инвестиции.месяц) КАК месяц,
       acquisitions.companies_acquired,
       investments.companies_rec_investment
  ИЗ (
        ВЫБРАТЬ приобретенный_месяц КАК месяц,
               COUNT (DISTINCT company_permalink) AS companies_acquired
          ИЗ учебника.crunchbase_acquisitions
         ГРУППА ПО 1
       ) приобретения

  ПОЛНОЕ СОЕДИНЕНИЕ (
        ВЫБЕРИТЕ funded_month AS месяц,
               COUNT (DISTINCT company_permalink) AS companies_rec_investment
          ИЗ tutorial.crunchbase_investments
         ГРУППА ПО 1
       )инвестиции

    ON acquisitions.month = investments.month
 ЗАКАЗАТЬ ПО 1 DESC
  

Примечание. Мы использовали приведенное выше значение FULL JOIN на тот случай, если в одной таблице были наблюдения за месяц, а в другой — нет. Мы также использовали COALESCE для отображения месяцев, когда в подзапросе приобретений не было записей о месяцах (предположительно, в эти месяцы не было приобретений).Мы настоятельно рекомендуем вам повторно запустить запрос без некоторых из этих элементов, чтобы лучше понять, как они работают. Вы также можете запускать каждый из подзапросов независимо, чтобы лучше понять их.

Практическая задача

Напишите запрос, который подсчитывает количество основанных и приобретенных компаний по кварталам, начиная с первого квартала 2012 года. Создайте агрегаты в двух отдельных запросах, а затем присоедините их.

Попробуй это Посмотреть ответ

Подзапросы и СОЮЗЫ

Для этого следующего раздела мы будем заимствовать непосредственно из урока по UNION — снова используя данные Crunchbase:

  ВЫБРАТЬ *
  ИЗ учебника.crunchbase_investments_part1

 СОЮЗ ВСЕ

 ВЫБРАТЬ *
   ИЗ tutorial.crunchbase_investments_part2
  

Определенно не редкость, когда набор данных разбивается на несколько частей, особенно если данные проходят через Excel в любой момент (Excel может обрабатывать только ~ 1 млн строк на электронную таблицу). Две таблицы, использованные выше, можно рассматривать как разные части одного и того же набора данных — вам почти наверняка захочется выполнять операции со всем комбинированным набором данных, а не с отдельными частями.Вы можете сделать это с помощью подзапроса:

  ВЫБРАТЬ СЧЕТЧИК (*) КАК total_rows
  ИЗ (
        ВЫБРАТЬ *
          ИЗ tutorial.crunchbase_investments_part1

         СОЮЗ ВСЕ

        ВЫБРАТЬ *
          ИЗ tutorial.crunchbase_investments_part2
       ) sub
  

Это довольно просто. Попробуйте сами:

Практическая задача

Напишите запрос, который ранжирует инвесторов из приведенного выше комбинированного набора данных по общему количеству вложенных ими инвестиций.

Попробуй это Посмотреть ответ

Практическая задача

Напишите запрос, который выполняет то же действие, что и в предыдущей задаче, за исключением компаний, которые все еще работают. Подсказка: рабочий статус находится в tutorial.crunchbase_companies .

Попробуй это Посмотреть ответ

Пример вопроса собеседования с вложенным подзапросом SQL

Пример вопроса собеседования с вложенным подзапросом SQL


Обзор вложенных запросов

Вложенный запрос SQL, также известный как подзапрос или подзапрос, представляет собой метод запроса SELECT, встроенный в другой запрос.Это эффективный способ получить желаемый результат, для которого может потребоваться несколько шагов запроса, или для обработки взаимозависимых запросов.

Когда использовать вложенные подзапросы

Вложенные подзапросы можно использовать несколькими способами:

  • Вы можете выполнять запросы по подзапросам (например, выбирать из подзапроса)
  • Вы можете заменить одномерные массивы (например, типичный список элементов) и объединения отдельных полей одним подзапросом в предложении WHERE или HAVING.

Чтобы использовать подзапрос, необходимо соблюдать несколько синтаксических правил:

  • Подзапрос необходимо заключить в круглые скобки
  • В зависимости от используемого механизма SQL может потребоваться псевдоним для данного подзапроса
  • При использовании в предложении WHERE или HAVING оператор SELECT подзапроса может возвращать только одно оцениваемое поле

Пример вопроса на собеседовании SQL с использованием вложенного подзапроса

Предположим, вам дана следующая таблица, показывающая продажи компании:

Таблица: sales_info

дата sale_id sale_usd
2020-01-05 1111 93695
2020-01-07 1112 879617
2020-01-07 1113 752878

Рассчитайте совокупный процент от общего объема продаж в данный день. Выходные данные таблицы должны выглядеть как в приведенном ниже примере таблицы.

дата pct_total_sales
2020-01-05 Х%
2020-01-07 Y%

Вы можете проработать этот пример, используя интерактивную скрипту SQL здесь.

Прежде чем мы начнем писать SQL, мы разбиваем вопрос на шаги:

  1. Рассчитать дневную сумму продаж
  2. Вычислить совокупную сумму ежедневных продаж и общих продаж за все дни
  3. Разделите ежедневный общий объем продаж на совокупную сумму

1. Рассчитайте дневную сумму продаж

Сначала мы напишем базовый запрос, который на следующем шаге станет подзапросом. В приведенном ниже запросе рассчитывается общая сумма продаж за день, и вы можете взаимодействовать с запросом с помощью этой скрипки SQL.

 

ВЫБРАТЬ

# нам нужно просуммировать sale_usd по дате

дата

,

сум (sale_usd) как total_usd

ИЗ sales_info

# поскольку мы собираем sale_usd по дате, нам нужно

# нужно сгруппировать по дате

ГРУППА ПО дате

2. Рассчитайте совокупную сумму ежедневных продаж и общих продаж за все дни

Запрос ниже вычисляет кумулятивную сумму ежедневных общих продаж и общих продаж за все дни.Вы можете взаимодействовать с приведенным ниже запросом с помощью этой скрипки SQL.

На этом шаге вы заметите, что мы строим запрос на основе предыдущего запроса из шага выше. Чтобы успешно создать подзапрос, нам нужно было заключить подзапрос в круглые скобки и обеспечить псевдоним таблицы (поскольку мы используем MySQL, обратите внимание, что это не является требованием для некоторых вариантов SQL). Нам также необходимо убедиться, что мы включили все поля, необходимые для внешнего запроса (например, дату и общий объем продаж).

 

ВЫБРАТЬ

# в этом запросе мы не группируем по, так как мы используем оконную функцию

дата

,

СУММА (total_usd) ВЫШЕ (

ORDER BY дата ASC строк

МЕЖДУ неограниченной предыдущей и текущей строкой)

как cum_total, # это оконная функция для

# рассчитать кумулятивную сумму

SUM (total_usd) OVER () as total # это оконная функция для

# подсчитать сумму

ОТ (

ВЫБРАТЬ

# нам нужно просуммировать sale_usd по дате

дата

,

сум (sale_usd) как total_usd

ИЗ sales_info

# поскольку мы собираем sale_usd по дате, нам нужно

# необходимо сгруппировать по дате

ГРУППА ПО дате

) as q1 # мы создаем псевдоним для этой таблицы в соответствии с требованиями MySQL

3.Разделите совокупный общий объем продаж на совокупную сумму

Последний шаг — разделить cum_total на сумму. Мы можем выполнить это на том же шаге, что и выше (просто разделив две оконные функции), или мы можем создать подзапрос поверх предыдущего шага. В приведенном ниже запросе используется другой подзапрос, в результате чего конечный запрос имеет 2 вложенных подзапроса. Вы можете взаимодействовать с приведенным ниже запросом с помощью этой скрипки SQL.

 

ВЫБРАТЬ

дата

,

100 * cum_total / total как

ОТ (

# в этом запросе мы не группируем по

# поскольку мы используем оконную функцию

ВЫБРАТЬ

дата

,

SUM (total_usd) OVER (ORDER BY дата ASC

строк МЕЖДУ неограниченной предыдущей и текущей строкой)

как cum_total, # это оконная функция для

# рассчитать кумулятивную сумму

SUM (total_usd) OVER () as total # это оконная функция

# для расчета суммы

ОТ (

ВЫБРАТЬ

# нам нужно просуммировать sale_usd по дате

дата

,

сум (sale_usd) как total_usd

ИЗ sales_info

# поскольку мы собираем sale_usd по дате, нам нужно

# нужно сгруппировать по дате

ГРУППА ПО дате

) as q1 # мы создаем псевдоним для этой таблицы в соответствии с требованиями MySQL

) как q2

Вложенное агрегирование: выполнение упорядоченных вычислений в одном запросе

При вложенном агрегировании вы можете выполнить запрос NRQL, а затем выполнить дополнительные вычисления, используя результаты этого запроса.Вложенная агрегация предоставляет возможности NRQL, аналогичные классу подзапросов или подзапросов SQL, где подзапрос находится в предложении FROM внешнего запроса.

Ответьте на сложные вопросы одним запросом

Вложенная агрегация может помочь вам ответить на подобные вопросы без создания нескольких запросов:

  • Могу ли я подсчитать количество запросов в минуту для моего приложения, а затем получить максимальное количество запросов в минуту для последнего час?
  • Могу ли я вычислить среднюю загрузку ЦП на всех моих серверах и перечислить только те, у которых загрузка превышает 90%?
  • Могу ли я выяснить, какой процент отказов сразу же вернулся из всех моих пользовательских сеансов?

Вложенная структура запроса агрегирования и предложения

Каждый запрос NRQL должен начинаться с оператора SELECT или предложения FROM .Вложенный запрос агрегирования использует как оператор SELECT, , так и предложение FROM и применяет их ко всему запросу или запросам, содержащимся в круглых скобках.

Полный и правильно отформатированный вложенный запрос агрегации будет выглядеть примерно так:

  

Функция SELECT (атрибут)

Функция SELECT (атрибут)

Еще несколько деталей о поведении запроса и предложения:

  • Вложенный запросы могут быть более двух уровней.
  • И TIMESERIES , и FACET можно применять к любой части вложенного запроса, и они не обязательно должны быть идентичными на всех уровнях. Предложения
  • SINCE , UNTIL и COMPARE WITH применяются ко всему запросу и могут использоваться только на самом внешнем уровне.

Примеры вложенных запросов агрегирования

Вот несколько примеров вложенных запросов.

Общее количество транзакций и максимальная скорость отклика в течение одной минуты

В этом примере внутренний запрос сначала подсчитывает транзакции для myApp за каждые последние 60 минут, а затем внешний запрос возвращает наивысшую частоту запросов в течение 1 минуты.

Кроме того, давая имя результату первого запроса (как rpm), вы можете создать метку для возвращаемого значения. Без добавления метки этот запрос вернет значение как счетчик для использования во внешнем запросе.

Среднее использование ЦП и загрузка ЦП более 90%

В этом примере внутренний запрос вычисляет среднее использование ЦП для всех хостов, затем внешний запрос фильтрует результаты до только хостов с использованием ЦП выше опасного порога (90% ).

  

ВЫБРАТЬ среднее (cpuPercent) как процессор

Просмотры страниц в каждом пользовательском сеансе и количество сеансов только с одним просмотром страницы

В этом примере внутренний запрос вычисляет количество событий PageView в каждом пользовательском сеансе, затем внешний запрос вычисляет, какой процент этих сеансов имел только одно связанное представление.

  

SELECT процент (count (*), WHERE sessionLength = 1)

SELECT count (*) as sessionLength

Для получения дополнительной помощи

Если вам нужна дополнительная помощь, ознакомьтесь с этими ресурсами поддержки и обучения:

Вложенный запрос | Ссылка на Elasticsearch [7.11]

Многоуровневые вложенные запросыправить

Чтобы увидеть, как работают многоуровневые вложенные запросы, сначала вам нужен индекс с вложенными полями. Следующий запрос определяет сопоставления для драйверов index. с вложенными составляют поля и модели .

 PUT / драйверы
{
  "mappings": {
    "характеристики": {
      "Водитель": {
        "тип": "вложенный",
        "характеристики": {
          "фамилия": {
            "тип": "текст"
          },
          "средство передвижения": {
            "тип": "вложенный",
            "характеристики": {
              "делать": {
                "тип": "текст"
              },
              "модель": {
                "тип": "текст"
              }
            }
          }
        }
      }
    }
  }
} 

Затем проиндексируйте некоторые документы в индекс драйверов .

 PUT / драйверы / _doc / 1
{
  "Водитель" : {
        "last_name": "МакКуин",
        "средство передвижения" : [
            {
                "make": "Powell Motors",
                «модель»: «Каньонеро»
            },
            {
                "make": "Миллер-Метеор",
                «модель»: «Экто-1»
            }
        ]
    }
}

PUT / drivers / _doc / 2? Обновить
{
  "Водитель" : {
        "last_name": "Хадсон",
        "средство передвижения" : [
            {
                "make": "Мифунэ",
                «модель»: «Мах пять»
            },
            {
                "make": "Миллер-Метеор",
                «модель»: «Экто-1»
            }
        ]
    }
} 

Теперь вы можете использовать многоуровневый вложенный запрос для сопоставления документов на основе полей сделайте и модели .

 GET / драйверы / _search
{
  "запрос": {
    "вложенный": {
      "путь": "водитель",
      "запрос": {
        "вложенный": {
          "path": "driver.vehicle",
          "запрос": {
            "bool": {
              "должен": [
                {"match": {"driver.vehicle.make": "Powell Motors"}},
                {"match": {"driver.vehicle.model": "Canyonero"}}
              ]
            }
          }
        }
      }
    }
  }
} 

Поисковый запрос возвращает следующий ответ:

 {
  «взял»: 5,
  "timed_out": ложь,
  "_shards": {
    «всего»: 1,
    «успешно»: 1,
    "пропущено": 0,
    "не удалось": 0
  },
  "хиты" : {
    "общий" : {
      «значение»: 1,
      "отношение": "экв"
    },
    «max_score»: 3.7349272, г.
    "хиты" : [
      {
        "_index": "драйверы",
        "_type": "_doc",
        "_id": "1",
        "_score": 3,7349272,
        "_источник" : {
          "Водитель" : {
            "last_name": "МакКуин",
            "средство передвижения" : [
              {
                "make": "Powell Motors",
                «модель»: «Каньонеро»
              },
              {
                "make": "Миллер-Метеор",
                «модель»: «Экто-1»
              }
            ]
          }
        }
      }
    ]
  }
} 

Программное обеспечение Столярные изделия:

Добро пожаловать в очередной выпуск лекции Software Carpentry о базах данных с использованием Microsoft Access.В этом выпуске около вложенных запросов .

В Access мы можем вложить один запрос в другой, чтобы использовать результаты первого запроса вместо таблицы. Другими словами, запрос может предоставить источник данных, из которого другой запрос может выбирать данные, фильтровать, сортировать, агрегировать и т. Д. Это позволяет нам отвечать на такие вопросы, как «Кто из ученых работал более чем над одним проектом?»

Начнем с определения, над сколькими различными проектами работал каждый ученый.Мы можем начать с поиска отдельного списка проектов, над которыми работал каждый ученый, с использованием уникальных ценностей. Мы хотим подсчитать, сколько проектов указано здесь для каждого ученого. Поскольку подсчет — это агрегирование, нам нужно использовать результаты этого запроса в качестве входных данных для отдельного запроса, который выполняет агрегирование.

Чтобы вложить этот запрос в качестве источника для более крупного запроса, мы начнем с сохранения этого запроса как «ProjectsByScientist». Затем мы создаем второй запрос. Когда мы запускаем запрос, вместо добавления существующей таблицы мы щелкаем вкладку запросов и добавляем запрос «ProjectsByScientist».Теперь мы можем использовать этот запрос как таблицу и агрегировать значения, нажимая «итоги», группируя по идентификатору входа и считая «проект». Теперь, если мы хотим увидеть список только ученых, которые работали над более чем одним проектом, мы можем отфильтровать это количество, чтобы оно было больше единицы, и не отображать столбец проекта.

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

Есть и другие вещи, которые мы можем делать с вложенными запросами, например, использовать результаты одного запроса для фильтрации результатов другого запроса. Это позволяет нам делать такие вещи, как определение или ученых, которые экспериментировали с путешествиями во времени. Но эти типы вложенных запросов или подзапросов нельзя сгенерировать с помощью графического интерфейса Access. Они требуют, чтобы мы использовали язык структурированных запросов, язык программирования, обычно называемый «SQL» или «продолжением».Если вам интересно, как это сделать, ознакомьтесь с лекциями Software Carpentry по базам данных с использованием SQL.

В этом скринкасте мы представили идею вложенных запросов. Мы видели, что вы можете использовать вложенный запрос вместо таблицы, чтобы ответить на более сложные вопросы, чем вы могли бы использовать отдельный запрос.

sql — предотвращение вложенных запросов

Это действительно зависит, у меня были ситуации, когда я улучшал некоторые запросы с помощью подзапросов.

Факторы, которые мне известны:

  • , если подзапрос использует поля из внешнего запроса для сравнения или нет (коррелировано или нет)
  • , если связь между внешним запросом и подзапросом покрывается индексами
  • , если в соединениях нет пригодных индексов, а подзапрос не коррелирован и возвращает небольшой результат, его может быть быстрее использовать
  • Я также сталкивался с ситуациями, когда преобразование запроса, который использует порядок по, в запрос, который его не использует, а затем превращение его в простой подзапрос и сортировку, которые улучшают производительность в mysql

В любом случае, всегда полезно тестировать разные варианты (с SQL_NO_CACHE, пожалуйста), и превращение коррелированных запросов в соединения — хорошая практика.

Я бы даже сказал, что это очень полезная практика.

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

РЕДАКТИРОВАТЬ: Процедурное против реляционного
Мышление в терминах операций над множеством и процедурного сводится к эквивалентности в некоторых выражениях алгебры множеств, например, выбор по объединению эквивалентен объединению выборок.Между ними нет разницы.
Но когда вы сравниваете две процедуры, например, применяете критерии выбора к каждому элементу объединения с помощью создания объединения, а затем применяете выбор, это две совершенно разные процедуры, которые могут иметь очень разные свойства (например, использование ЦП, Ввод / вывод, память).

Идея реляционных баз данных заключается в том, что вы не пытаетесь описать, как получить результат (процедуру), а только то, что вы хотите, и что система управления базами данных выберет лучший путь (процедуру) для выполнения вашего запроса.Вот почему SQL называется языком 4-го поколения (4GL).

Один из приемов, который поможет вам в этом, — напомнить себе, что кортежи не имеют внутреннего порядка (элементы набора неупорядочены). Другой — понимание того, что реляционная алгебра является достаточно всеобъемлющей и позволяет переводить запросы (требования) непосредственно в SQL (если семантика вашей модели хорошо представляет проблемное пространство, или, другими словами, если значение, прикрепленное к имени ваших таблиц и отношений, выполнено правильно , или, другими словами, если ваша база данных хорошо спроектирована).

Следовательно, не надо думать как, только что.

В вашем случае это было просто предпочтение по сравнению с коррелированными запросами, так что, возможно, я не говорю вам ничего нового, но вы подчеркнули этот момент, отсюда и комментарий.

Я думаю, что если бы вы были полностью довольны всеми правилами, которые преобразуют запросы из одной формы в другую (такие как правила распределения), вы бы не предпочли коррелированные подзапросы (чтобы все формы были равны).

(Примечание: выше обсуждается теоретическая основа, важная для проектирования базы данных; практически вышеуказанные концепции отклоняются — не все эквивалентные перезаписи запроса обязательно выполняются с такой скоростью, кластеризованные первичные ключи действительно заставляют таблицы иметь порядок наследования на диске и т. эти отклонения являются всего лишь отклонениями; тот факт, что не все эквивалентные запросы выполняются так быстро, является несовершенством самой СУБД, а не концепций, лежащих в основе нее)

(PDF) Вложенные запросы SQL в SPARQL

(1) Если 𝑊⊂𝑉 — это набор переменных и 𝐻 ​​- это набор тройных шаблонов (называемый шаблоном графика

), то выражения SELECT𝑊, CONSTRUCT 𝐻 и ASK равны

. формы запроса результатов.

(2) Если 𝑢∈𝐼и 𝑄𝐶 является запросом формы (CONSTRUCT 𝐻, 𝐹, 𝑃), то

выражений FROM 𝑢 и FROM NAMED являются предложениями набора данных.

(3) Ограничение фильтра определяется рекурсивно следующим образом:

–Если? 𝑋,? 𝑌∈𝑉и 𝑣∈𝐼∪𝐿, то? 𝑋 = 𝑣,? 𝑋 =? 𝑌, и граница (? 𝑋)

являются (атомарные) ограничения фильтра 5.

–Если 𝑢∈𝑇, 𝜃 — это скалярный оператор сравнения (=, ∕ =, <, <=,>,> =), а

𝑄? 𝑋 — это запрос формы (SELECT? 𝑋, 𝐹, 𝑃) , то выражения

(𝑢 𝜃 НЕКОТОРЫЕ (𝑄? 𝑋)), (𝑢 𝜃 ALL (𝑄? 𝑋)) и (𝑢IN (𝑄? 𝑋)) являются фильтрующими ограничениями

.

–Если 𝑄𝐴 это запрос формы (ASK, 𝑃, 𝑃), то выражение EXISTS (𝑄𝐴)

является ограничением фильтра.

–Если 𝐶1 и 𝐶2 являются ограничениями фильтра, то (¬𝐶1), (𝐶1∧𝐶2) и (𝐶1∨𝐶2)

являются (сложными) ограничениями фильтра.

(4) Шаблон графика определяется рекурсивно следующим образом:

–Тройной шаблон — это шаблон графика.

–Если 𝑃1 и 𝑃2 являются образцами графиков, то выражения (𝑃1AND 𝑃2),

(𝑃1OPT 𝑃2), (𝑃1UNION 𝑃2) и (𝑃1MINUS 𝑃2) являются образцами графиков.6

–Если 𝑃это шаблон графика и 𝑢∈𝐼∪𝑉, то выражение (𝑢GRAPH 𝑃)

представляет собой шаблон графика.

–Если это шаблон графика и ограничение фильтра, то выражение

(«ФИЛЬТР») является шаблоном графика.

Пусть 𝑄 = (𝑅, 𝐹, 𝑃) — запрос. Запрос 𝑄 ′ вложен в 𝑄if и только если 𝑄 ′

встречается в шаблоне графа 𝑃, то есть когда i.e.′ вложен в 𝑃. В таком случае 𝑄 — это

, известный как внешний запрос, а 𝑄 ′ — как внутренний запрос.