Sql вложенные запросы select: Вложенные SQL запросы

Содержание

Вложенные запросы SQL — CodeTown.ru

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

Введение

Итак, само название говорит о том, что запрос во что-то вложен. Так вот, вложенный запрос в SQL означает, что запрос select выполняется в еще одном запросе select — на самом деле вложенность может быть и многоуровневой, то есть select в select в select и т.д.

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

Структура ранее созданных таблиц

Прежде чем перейдем к простому примеру, напомним структуру наших таблиц, с которыми будем работать:

  • Таблица Salespeople (продавцы):
snumsnamecitycomm
1КоловановМосква10
2ПетровТверь25
3ПлотниковМосква22
4КучеровСанкт-Петербург28
5МалкинСанкт-Петербург18
6ШипачевЧелябинск30
7МозякинОдинцово25
8ПроворовМосква25
  • Таблица Customers (покупатели):
сnumсnamecityratingsnum
1ДесновМосква906
2КрасновМосква957
3КирилловТверь963
4ЕрмолаевОбнинск983
5КолесниковСерпухов985
6ПушкинЧелябинск904
7ЛермонтовОдинцово851
8БелыйМосква893
9ЧудиновМосква962
10ЛосевОдинцово938
  • Таблица Orders (заказы)
onumamtodatecnumsnum
10011282016-01-0194
100218002016-04-10107
10033482017-04-0821
10045002016-06-0733
10054992017-12-0454
10063202016-03-0354
1007802017-09-0271
10087802016-03-0713
10095602017-10-0737
10109002016-01-0868

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

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

Начнем с такого примера и для начала вспомним, как бы делали этот запрос ранее: посмотрели бы в таблицу Salespeople, определили бы snum продавца Колыванова — он равен 1. И выполнили бы запрос SQL с помощью условия WHERE. Вот пример такого SQL запроса:

SELECT amt, odate
FROM orders 
WHERE snum = 1

Очевидно, какой будет вывод:

amtodate
3482017-04-08
802017-09-02

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

SELECT amt, odate
FROM orders
where snum = (SELECT snum
              FROM salespeople
              WHERE sname = 'Колованов')

В этом примере мы определяем с помощью вложенного запроса идентификатор snum по фамилии из таблицы salespeople, а затем, в таблице orders определяем по этому идентификатору нужные нам значения. Таким образом работают вложенные запросы SQL.

Рассмотрим еще один пример:
Показать уникальные номера и фамилии продавцов, которые провели сделки в 2016 году.

SELECT snum, sname
FROM salespeople
where snum IN (SELECT snum
              FROM orders
              WHERE YEAR(odate) = 2016)

Этот SQL запрос отличается тем, что вместо знака = здесь используется оператор IN. Его следует использовать в том случае, если вложенный подзапрос SQL возвращает несколько значений. То есть в запросе происходит проверка, содержится ли идентификатор snum из таблицы salespeople в массиве значений, который вернул вложенный запрос. Если содержится, то SQL выдаст фамилию этого продавца.

Получился такой результат:

snumsname
3Плотников
4Кучеров
7Мозякин
8Проворов

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

Те примеры, которые мы уже рассмотрели, сравнивали в условии WHERE одно поле. Это конечно хорошо, но стоит отметить, что в SQL предусмотрена возможность сравнения сразу нескольких полей, то есть можно использовать вложенный запрос с несколькими параметрами.

Вывести пары покупателей и продавцов, которые осуществили сделку между собой в 2017 году.

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

SELECT cname as 'Покупатель', sname as 'Продавец'
FROM customers cus, salespeople sal
where (cus.cnum, sal.snum) IN (SELECT cnum, snum
              FROM orders
              WHERE YEAR(odate) = 2017)

Вывод запроса:

ПокупательПродавец
КрасновКолованов
КолесниковКучеров
ЛермонтовКолованов
КирилловМозякин

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

На самом деле, такой запрос SQL используется крайне редко, обычно используют оператор INNER JOIN, о котором будет сказано в следующей статье.

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

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

1.Напишите запрос, который бы использовал подзапрос для получения всех Заказов для покупателя с фамилией Краснов. Предположим, что вы не знаете номера этого покупателя, указываемого в поле cnum.

SELECT *
FROM orders
where cnum = (SELECT cnum
              FROM customers
              WHERE cname = 'Краснов')

2. Напишите запрос, который вывел бы имена и рейтинг всех покупателей, которые имеют Заказы, сумма которых выше средней.

SELECT cname, rating
FROM customers
where cnum IN (SELECT cnum
              FROM orders
              WHERE amt > (SELECT AVG(amt)
                          from orders))

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

SELECT snum, SUM(AMT) 
FROM orders 
GROUP BY snum 
HAVING SUM(amt) > (SELECT MAX(amt) 
                        FROM orders)

4. Напишите запрос, который бы использовал подзапрос для получения всех Заказов для покупателей проживающих в Москве.

SELECT *
FROM orders
where cnum IN (SELECT cnum
              FROM customers
              WHERE city =  'Москва')

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

SELECT amt, odate
FROM orders
WHERE AMT = (SELECT MAX(AMT)
             FROM orders)

6. Определить покупателей, совершивших сделки с максимальной суммой приобретений.

SELECT cname
FROM customers
WHERE cnum IN (SELECT cnum
               FROM orders
               WHERE amt = (SELECT MAX(amt)
                            FROM orders))

Заключение

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

azure-docs.ru-ru/sql-query-subquery.md at master · MicrosoftDocs/azure-docs.ru-ru · GitHub

titledescriptionauthorms. servicems.subservicems.topicms.datems.authorms.openlocfilehashms.sourcegitcommitms.translationtypems.contentlocalems.lasthandoffms.locfileid

Вложенные запросы SQL для Azure Cosmos DB

Сведения о вложенных запросах SQL и их типичных сценариях использования и различных типах вложенных запросов в Azure Cosmos DB

timsander1

cosmos-db

cosmosdb-sql

conceptual

12/02/2019

tisande

f5f209229d17a2587258d21ee90e7560e629d082

867cb1b7a1f3a1f0b427282c648d411d0ca4f81f

MT

ru-RU

03/19/2021

93340861

[!INCLUDEappliesto-sql-api]

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

В этой статье описываются вложенные запросы SQL и их распространенные варианты использования в Azure Cosmos DB. Все примеры запросов в этом документе можно выполнить для набора данных информации питании, который предварительно загружен на Площадка для тестирования запросов Azure Cosmos DB.

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

Существует два основных типа вложенных запросов:

  • Коррелированный: вложенный запрос, который ссылается на значения из внешнего запроса. Вложенный запрос вычисляется один раз для каждой строки, обрабатываемой внешним запросом.
  • Некоррелированный: вложенный запрос, который не зависит от внешнего запроса. Его можно выполнять самостоятельно, не полагаясь на внешний запрос.

[!NOTE]
Azure Cosmos DB поддерживает только коррелированные вложенные запросы.

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

  • Table: возвращает несколько строк и несколько столбцов.
  • Множественное значение: возвращает несколько строк и один столбец.
  • Scalar: Возвращает одну строку и один столбец.

SQL-запросы в Azure Cosmos DB всегда возвращают один столбец (простое значение или сложный документ). Таким образом, в Azure Cosmos DB применимы только многозначные и скалярные вложенные запросы. Вложенный запрос с несколькими значениями можно использовать только в предложении FROM в качестве реляционного выражения. Скалярный вложенный запрос можно использовать в качестве скалярного выражения в предложении SELECT или WHERE или в качестве реляционного выражения в предложении FROM.

Вложенные запросы с несколькими значениями

Вложенные запросы с несколькими значениями возвращают набор документов и всегда используются в предложении FROM. Они используются для:

  • Оптимизация выражений соединений.
  • Оценка дорогостоящих выражений один раз и многократная ссылка.

Выражения оптимизации соединений

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

Обратите внимание на следующий запрос:

SELECT Count(1) AS Count
FROM c
JOIN t IN c.tags
JOIN n IN c.nutrients
JOIN s IN c.servings
WHERE t.name = 'infant formula' AND (n.nutritionValue > 0 
AND n.nutritionValue < 10) AND s.amount > 1

Для этого запроса индекс будет соответствовать любому документу с тегом с именем «Формула новорожденный». Это элемент нутриент со значением от 0 до 10 и обслуживающим элементом с суммой больше 1. Выражение JOIN здесь выполняет перекрестное произведение всех элементов тегов, нутриентс и обслуживает массивы для каждого соответствующего документа до применения любого фильтра.

Затем предложение WHERE применит предикат фильтра для каждого <ного кортежа c, t, n, s>. Например, если в соответствующем документе в каждом из трех массивов было 10 элементов, оно будет расширено до 1 x 10 x 10 x 10 (то есть 1 000) кортежей. С помощью вложенных запросов можно фильтровать соединяемые элементы массива перед присоединением к следующему выражению.

Этот запрос эквивалентен предыдущему, но использует вложенные запросы:

SELECT Count(1) AS Count
FROM c
JOIN (SELECT VALUE t FROM t IN c.tags WHERE t.name = 'infant formula')
JOIN (SELECT VALUE n FROM n IN c.nutrients WHERE n.nutritionValue > 0 AND n.nutritionValue < 10)
JOIN (SELECT VALUE s FROM s IN c.servings WHERE s.amount > 1)

Предположим, что только один элемент в массиве Tags соответствует фильтру, а для нутриентс и обслуживания массивов существует пять элементов. Затем выражения объединения разворачиваются до 1 x 1 x 5 x 5 = 25 элементов, а не 1 000 элементов в первом запросе.

Многократное вычисление и ссылка

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

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

SELECT c.id, udf.GetMaxNutritionValue(c.nutrients) AS MaxNutritionValue
FROM c
WHERE udf.GetMaxNutritionValue(c.nutrients) > 100

Ниже приведен эквивалентный запрос, запускающий UDF только один раз:

SELECT TOP 1000 c.id, MaxNutritionValue
FROM c
JOIN (SELECT VALUE udf.GetMaxNutritionValue(c.nutrients)) MaxNutritionValue
WHERE MaxNutritionValue > 100

[!NOTE]
Учитывайте поведение перекрестного произведения выражений JOIN. Если выражение UDF может принимать значение undefine, следует убедиться, что выражение JOIN всегда создает одну строку, возвращая объект из вложенного запроса, а не значение напрямую.

Вот похожий пример, возвращающий объект, а не значение:

SELECT TOP 1000 c.id, m.MaxNutritionValue
FROM c
JOIN (SELECT udf.GetMaxNutritionValue(c.nutrients) AS MaxNutritionValue) m
WHERE m.MaxNutritionValue > 100

Этот подход не ограничивается UDF. Он применяется к любому потенциально дорогостоящему выражению. Например, можно использовать тот же подход с математической функцией avg :

SELECT TOP 1000 c.id, AvgNutritionValue
FROM c
JOIN (SELECT VALUE avg(n.nutritionValue) FROM n IN c.nutrients) AvgNutritionValue
WHERE AvgNutritionValue > 80

Имитировать соединение с внешними эталонными данными

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

Например, рассмотрим следующий набор ссылочных данных:

Единица измеренияимя;МножительБазовая единица
NGМикрограмматика1,00 e-09Gram
μгмикрограм1,00 e-06Gram
mgмиллиграм1,00 e-03Gram
нGram1,00 e + 00Gram
кгКилограмм1,00 e + 03Gram
MGмегаграм1,00 e + 06Gram
GGгигаграм1,00 e + 09Gram
nJнаножауле1,00 e-09жауле
μжмикрожауле1,00 e-06жауле
mJмиллижауле1,00 e-03жауле
Jжауле1,00 e + 00жауле
kJкиложауле1,00 e + 03жауле
MJмегажауле1,00 e + 06жауле
гжгигажауле1,00 e + 09жауле
Calкалорие1,00 e + 00калорие
ккалкалорие1,00 e + 03калорие
IUМеждународные единицы

Следующий запрос имитирует соединение с этими данными, чтобы добавить в выходные данные имя единицы измерения:

SELECT TOP 10 n. id, n.description, n.nutritionValue, n.units, r.name
FROM food
JOIN n IN food.nutrients
JOIN r IN (
    SELECT VALUE [
        {unit: 'ng', name: 'nanogram', multiplier: 0.000000001, baseUnit: 'gram'},
        {unit: 'µg', name: 'microgram', multiplier: 0.000001, baseUnit: 'gram'},
        {unit: 'mg', name: 'milligram', multiplier: 0.001, baseUnit: 'gram'},
        {unit: 'g', name: 'gram', multiplier: 1, baseUnit: 'gram'},
        {unit: 'kg', name: 'kilogram', multiplier: 1000, baseUnit: 'gram'},
        {unit: 'Mg', name: 'megagram', multiplier: 1000000, baseUnit: 'gram'},
        {unit: 'Gg', name: 'gigagram', multiplier: 1000000000, baseUnit: 'gram'},
        {unit: 'nJ', name: 'nanojoule', multiplier: 0.000000001, baseUnit: 'joule'},
        {unit: 'µJ', name: 'microjoule', multiplier: 0.000001, baseUnit: 'joule'},
        {unit: 'mJ', name: 'millijoule', multiplier: 0.001, baseUnit: 'joule'},
        {unit: 'J', name: 'joule', multiplier: 1, baseUnit: 'joule'},
        {unit: 'kJ', name: 'kilojoule', multiplier: 1000, baseUnit: 'joule'},
        {unit: 'MJ', name: 'megajoule', multiplier: 1000000, baseUnit: 'joule'},
        {unit: 'GJ', name: 'gigajoule', multiplier: 1000000000, baseUnit: 'joule'},
        {unit: 'cal', name: 'calorie', multiplier: 1, baseUnit: 'calorie'},
        {unit: 'kcal', name: 'Calorie', multiplier: 1000, baseUnit: 'calorie'},
        {unit: 'IU', name: 'International units'}
    ]
)
WHERE n. units = r.unit

скалярные вложенные запросы;

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

Однако использование скалярного вложенного запроса не всегда помогает оптимизировать. Например, передача скалярного вложенного запроса в качестве аргумента в системную или определяемую пользователем функцию не дает никаких преимуществ в использовании единицы ресурсов (RU) или задержке.

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

  • Скалярные вложенные запросы в простых выражениях
  • Агрегирование скалярных вложенных запросов

Скалярные вложенные запросы в простых выражениях

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

Рассмотрим несколько примеров.

Пример 1

SELECT 1 AS a, 2 AS b

Можно переписать этот запрос с помощью скалярного вложенного запроса простого выражения, чтобы:

SELECT (SELECT VALUE 1) AS a, (SELECT VALUE 2) AS b

Эти выходные данные создаются в обоих запросах:

[
  { "a": 1, "b": 2 }
]

Пример 2

SELECT TOP 5 Concat('id_', f.id) AS id
FROM food f

Можно переписать этот запрос с помощью скалярного вложенного запроса простого выражения, чтобы:

SELECT TOP 5 (SELECT VALUE Concat('id_', f.id)) AS id
FROM food f

Выходные данные запроса:

[
  { "id": "id_03226" },
  { "id": "id_03227" },
  { "id": "id_03228" },
  { "id": "id_03229" },
  { "id": "id_03230" }
]

Пример 3

SELECT TOP 5 f. id, Contains(f.description, 'fruit') = true ? f.description : undefined
FROM food f

Можно переписать этот запрос с помощью скалярного вложенного запроса простого выражения, чтобы:

SELECT TOP 10 f.id, (SELECT f.description WHERE Contains(f.description, 'fruit')).description
FROM food f

Выходные данные запроса:

[
  { "id": "03230" },
  { "id": "03238", "description":"Babyfood, dessert, tropical fruit, junior" },
  { "id": "03229" },
  { "id": "03226", "description":"Babyfood, dessert, fruit pudding, orange, strained" },
  { "id": "03227" }
]

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

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

Пример 1.

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

SELECT TOP 5 
    f. id, 
    (SELECT VALUE Count(1) FROM n IN f.nutrients WHERE n.units = 'mg'
) AS count_mg
FROM food f

Выходные данные запроса:

[
  { "id": "03230", "count_mg": 13 },
  { "id": "03238", "count_mg": 14 },
  { "id": "03229", "count_mg": 13 },
  { "id": "03226", "count_mg": 15 },
  { "id": "03227", "count_mg": 19 }
]

Пример 2

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

SELECT TOP 5 f.id, (
    SELECT Count(1) AS count, Sum(n.nutritionValue) AS sum 
    FROM n IN f.nutrients 
    WHERE n.units = 'mg'
) AS unit_mg
FROM food f

Выходные данные запроса:

[
  { "id": "03230","unit_mg": { "count": 13,"sum": 147.072 } },
  { "id": "03238","unit_mg": { "count": 14,"sum": 107.385 } },
  { "id": "03229","unit_mg": { "count": 13,"sum": 141.579 } },
  { "id": "03226","unit_mg": { "count": 15,"sum": 183.91399999999996 } },
  { "id": "03227","unit_mg": { "count": 19,"sum": 94. 788999999999987 } }
]

Пример 3

Вот запрос со статистическим вложенным запросом как в проекции, так и в фильтре:

SELECT TOP 5 
    f.id, 
    (SELECT VALUE Count(1) FROM n IN f.nutrients WHERE n.units = 'mg') AS count_mg
FROM food f
WHERE (SELECT VALUE Count(1) FROM n IN f.nutrients WHERE n.units = 'mg') > 20

Выходные данные запроса:

[
  { "id": "03235", "count_mg": 27 },
  { "id": "03246", "count_mg": 21 },
  { "id": "03267", "count_mg": 21 },
  { "id": "03269", "count_mg": 21 },
  { "id": "03274", "count_mg": 21 }
]

Более оптимальный способ написания этого запроса — соединение во вложенном запросе и ссылка на псевдоним вложенного запроса в предложениях SELECT и WHERE. Этот запрос более эффективен, поскольку необходимо выполнить вложенный запрос только внутри инструкции JOIN, а не в проекции и фильтре.

SELECT TOP 5 f.id, count_mg
FROM food f
JOIN (SELECT VALUE Count(1) FROM n IN f. nutrients WHERE n.units = 'mg') AS count_mg
WHERE count_mg > 20

Выражение EXISTs

Azure Cosmos DB поддерживает выражения EXISTs. Это совокупный скалярный вложенный запрос, встроенный в Azure Cosmos DB API SQL. EXISTs является логическим выражением, которое принимает выражение вложенного запроса и возвращает значение true, если вложенный запрос возвращает какие-либо строки. В противном случае возвращается значение false.

Так как API Azure Cosmos DB SQL не различает логические выражения и другие скалярные выражения, можно использовать в предложениях SELECT и WHERE. Это отличается от T-SQL, где логическое выражение (например, EXISTs, BETWEEN и IN) ограничено фильтром.

Если вложенный запрос EXISTs возвращает одиночное значение, которое не определено, то параметр EXISTs принимает значение false. Например, рассмотрим следующий запрос, результатом которого является значение false:

SELECT EXISTS (SELECT VALUE undefined)

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

SELECT EXISTS (SELECT undefined) 

Вложенный запрос будет заключать список значений в выбранном списке в объекте. Если выбранный список не содержит значений, вложенный запрос возвратит единственное значение » {} «. Это значение определено, поэтому EXISTs вычисляется как true.

Пример: перезапись ARRAY_CONTAINS и присоединение как существует

Распространенным вариантом использования ARRAY_CONTAINS является фильтрация документа по существованию элемента в массиве. В этом случае мы проверяя, содержит ли массив Tags элемент с именем «оранжевый».

SELECT TOP 5 f.id, f.tags
FROM food f
WHERE ARRAY_CONTAINS(f.tags, {name: 'orange'})

Вы можете переписать тот же запрос, чтобы использовать EXISTs:

SELECT TOP 5 f.id, f.tags
FROM food f
WHERE EXISTS(SELECT VALUE t FROM t IN f.tags WHERE t.name = 'orange')

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

Рассмотрим следующий запрос, который фильтруется на основе единиц и nutritionValue свойств в массиве:

SELECT VALUE c. description
FROM c
JOIN n IN c.nutrients
WHERE n.units= "mg" AND n.nutritionValue > 0

Для каждого документа в коллекции перекрестное произведение выполняется с элементами массива. Эта операция объединения позволяет фильтровать свойства в массиве. Однако этот запрос будет иметь большое количество запросов. Например, если в 1 000 документах в каждом массиве содержалось 100 элементов, оно будет расширено до 1 000 x 100 (т. е. 100 000) кортежей.

Использование EXISTs может помочь избежать этого дорогостоящего перекрестного произведения:

SELECT VALUE c.description
FROM c
WHERE EXISTS(
    SELECT VALUE n
    FROM n IN c.nutrients
    WHERE n.units = "mg" AND n.nutritionValue > 0
)

В этом случае вы фильтруете элементы массива внутри вложенного запроса EXISTs. Если элемент массива соответствует фильтру, то его проект и EXISTs будут иметь значение true.

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

SELECT TOP 1 c. description, EXISTS(
    SELECT VALUE n
    FROM n IN c.nutrients
    WHERE n.units = "mg" AND n.nutritionValue > 0) as a
FROM c

Выходные данные запроса:

[
    {
        "description": "Babyfood, dessert, fruit pudding, orange, strained",
        "a": true
    }
]

Выражение массива

Можно использовать выражение массива для проецирования результатов запроса в виде массива. Это выражение можно использовать только в предложении SELECT запроса.

SELECT TOP 1   f.id, ARRAY(SELECT VALUE t.name FROM t in f.tags) AS tagNames
FROM  food f

Выходные данные запроса:

[
    {
        "id": "03238",
        "tagNames": [
            "babyfood",
            "dessert",
            "tropical fruit",
            "junior"
        ]
    }
]

Как и в случае с другими вложенными запросами, возможны фильтры с выражением массива.

SELECT TOP 1 c.id, ARRAY(SELECT VALUE t FROM t in c. tags WHERE t.name != 'infant formula') AS tagNames
FROM c

Выходные данные запроса:

[
    {
        "id": "03226",
        "tagNames": [
            {
                "name": "babyfood"
            },
            {
                "name": "dessert"
            },
            {
                "name": "fruit pudding"
            },
            {
                "name": "orange"
            },
            {
                "name": "strained"
            }
        ]
    }
]

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

SELECT TOP 1 c.id, ARRAY(SELECT VALUE t.name FROM t in c.tags) as tagNames
FROM c
JOIN n IN (SELECT VALUE ARRAY(SELECT t FROM t in c.tags WHERE t.name != 'infant formula'))

Выходные данные запроса:

[
    {
        "id": "03238",
        "tagNames": [
            "babyfood",
            "dessert",
            "tropical fruit",
            "junior"
        ]
    }
]

Дальнейшие действия

  • Примеры . NET для Azure Cosmos DB
  • Данные документов модели

sql — использовать данные Select во вложенном операторе Select в MySQL

Задать вопрос

спросил

Изменено
3 года, 9 месяцев назад

Просмотрено
3к раз

У меня есть запрос в MySQL.

Полный запрос

 ВЫБЕРИТЕ
  tc.expense AS расход,
  tc.tour_sub_code,
  tc.login_id
ИЗ
  tc_wallet тс
ГДЕ tc.login_id = 'vinod.kumbala'
  И tc.expense = 'Суточные'
  И tc.delete_flag = 'F'
  И tc.status != 'отклонить'
 

Результат

 Расход Tour_sub_code login_id
ЕЖЕДНЕВНЫЕ СРЕДСТВА MOS-EUROPE100119 vinod.kumbala
ЕЖЕДНЕВНЫЙ РЕЗУЛЬТАТ Тест винод.кумбала
 

Сначала я извлекаю данные из таблицы tc_wallet .
Теперь мне нужно найти общее количество посещений для конкретного tour_sub_code . Счетчик посещений можно найти в таблице ttence_master для конкретного tour_sub_code .
Поэтому я включил вложенный запрос выбора, который равен

Вложенный выбор

 (SELECT
    СЧИТАТЬ(*)
  ИЗ
    (ВЫБРАТЬ
      *
    ИЗ
      `посещаемость_мастер`
    ГДЕ `delete_flag` = 'F'
      И login_id = 'vinod.kumbala'
      И `tour_sub_code` = tc.`tour_sub_code`
    СГРУППИРОВАТЬ ПО `device_date`) t1) AS newNoOfdays
 

Полный запрос

 ВЫБЕРИТЕ
      tc.expense AS расход,
      tc.tour_sub_code,
      tc.login_id,
      (ВЫБРАТЬ
        СЧИТАТЬ(*)
      ИЗ
        (ВЫБРАТЬ
          *
        ИЗ
          `посещаемость_мастер`
        ГДЕ `delete_flag` = 'F'
          И login_id = 'vinod.kumbala'
          И `tour_sub_code` = tc.`tour_sub_code`
        СГРУППИРОВАТЬ ПО `device_date`) t1) AS newNoOfdays
    ИЗ
      tc_wallet тс
    ГДЕ tc. login_id = 'vinod.kumbala'
      И tc.expense = 'Суточные'
      И tc.delete_flag = 'F'
      И tc.status != 'отклонить'
 

Теперь этот запрос дает мне ошибку как

Неизвестный столбец «tc.tour_sub_code» в «предложении where»

Ожидаемый результат

 Expense Tour_sub_code login_id Count
    ЕЖЕДНЕВНОЕ ПОЛОЖЕНИЕ MOS-EUROPE100119 vinod.kumbala 20
    ЕЖЕДНЕВНЫЙ РЕЗУЛЬТАТ Тест винод.кумбала 44
 

Могу ли я узнать, где я ошибаюсь?
Также есть ли другой способ получить результат, например, с помощью JOINS?

  • mysql
  • sql
  • sqlyog

В самом внутреннем подзапросе вы ссылаетесь на столбец из самого внешнего запроса. Это не разрешено для подзапросов в предложении FROM (производные таблицы). Однако вам не нужен этот подзапрос. Вам нужно COUNT(DISTINCT device_date)

Переписать

 (ВЫБРАТЬ
    СЧИТАТЬ(*)
  ИЗ
    (ВЫБРАТЬ
      *
    ИЗ
      `посещаемость_мастер`
    ГДЕ `delete_flag` = 'F'
      И login_id = 'vinod. kumbala'
      И `tour_sub_code` = tc.`tour_sub_code`
    СГРУППИРОВАТЬ ПО `device_date`) t1) AS newNoOfdays
 9от 0019 

до

 (ВЫБРАТЬ
    COUNT(DISTINCT устройство_дата)
  ОТ `attendance_master`
  ГДЕ `delete_flag` = 'F'
    И login_id = 'vinod.kumbala'
    И `tour_sub_code` = tc.`tour_sub_code`
) AS newNoOfdays
 

Вы также можете переписать полный запрос в запрос LEFT JOIN:

 SELECT
  tc.expense AS расход,
  tc.tour_sub_code,
  tc.login_id,
  COUNT(DISTINCT device_date) AS newNoOfdays
ОТ tc_wallet tc
ВЛЕВО ПРИСОЕДИНЯЙСЯ
  ВКЛ am.tour_sub_code = tc.tour_sub_code
  И am.delete_flag = 'F'
  И am.login_id = 'vinod.kumbala'
ГДЕ tc.login_id = 'vinod.kumbala'
  И tc.expense = 'Суточные'
  И tc.delete_flag = 'F'
  И tc.status != 'отклонить'
 

Попробуйте это:

 ВЫБЕРИТЕ
      tc.expense AS расход,
      tc.tour_sub_code,
      tc.login_id,
      подсчет(*) как подсчет
    ИЗ
      tc_wallet тс
    ВНУТРЕННЕЕ СОЕДИНЕНИЕ
      посещаемость_мастер утра
    НА
      tc. tour_sub_code = am.tour_sub_code И
      tc.login_id = am.login_id
    ГДЕ tc.login_id = 'vinod.kumbala'
      И tc.expense = 'Суточные'
      И tc.delete_flag = 'F'
      И tc.status != 'отклонить'
    ГРУППА ПО
      tc.expense AS расход,
      tc.tour_sub_code,
      tc.login_id
 

Попробуйте это ---

 ВЫБЕРИТЕ
      tc.expense AS расход,
      tc.tour_sub_code,
      tc.login_id,
      (ВЫБРАТЬ
        COUNT(утра*)
      ОТ `attendance_master` как am
        ГДЕ am.delete_flag = 'F'
          И am.login_id = 'vinod.kumbala'
          И am.tour_sub_code = tc.tour_sub_code
        СГРУППИРОВАТЬ ПО am.device_date) AS count
    ИЗ
      tc_wallet тс
    ГДЕ tc.login_id = 'vinod.kumbala'
      И tc.expense = 'Суточные'
      И tc.delete_flag = 'F'
      И tc.status != 'отклонить'
 

Вы можете попробовать это:

 выберите tc.expense AS расход,
        tc.tour_sub_code,
        tc.login_id,
        newNoOfdays.countVal
из tc_wallet тс
внутреннее соединение
        ( выберите tour_sub_code, count('A') 'countval'
            от attence_master ascs (без блокировки)
            группировать по tour_sub_code) как newNoOfdays
в newNoOfdays. tour_sub_code = tc.tour_sub_code
где tc.login_id = 'vinod.kumbala'
И tc.expense = 'Суточные'
И tc.delete_flag = 'F'
И tc.status != 'отклонить'
 

Зарегистрируйтесь или войдите в систему

Зарегистрируйтесь с помощью Google

Зарегистрироваться через Facebook

Зарегистрируйтесь, используя электронную почту и пароль

Опубликовать как гость

Электронная почта

Обязательно, но не отображается

Опубликовать как гость

Электронная почта

Требуется, но не отображается

sql server - Синтаксис вложенного выбора SQL

Задать вопрос

спросил

Изменено
2 года, 7 месяцев назад

Просмотрено
9к раз

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

Моя проблема сейчас связана с синтаксисом. Я не уверен, куда нужно идти, чтобы получить желаемый результат выше.

Вот что у меня есть на данный момент:

Таблицы OFFICE и AGENT:

 CREATE TABLE OFFICE
(
     OfficeID NVARCHAR(5) УНИКАЛЬНЫЙ,
     Адрес офиса NVARCHAR(18) НЕ NULL,
     ПЕРВИЧНЫЙ КЛЮЧ(OfficeID)
)
ИДТИ
СОЗДАТЬ ТАБЛИЧНЫЙ АГЕНТ
(
     AgentID NVARCHAR(8) УНИКАЛЬНЫЙ,
     OfficeID NVARCHAR(5) НЕ NULL,
     AgentType NVARCHAR(9) НЕ NULL,
     AgentFName NVARCHAR(10) НЕ NULL,
     ПЕРВИЧНЫЙ КЛЮЧ (АгентИд),
     ВНЕШНИЙ КЛЮЧ (OfficeID) ССЫЛКИ ОФИС
             НА УДАЛЕНИЕ КАСКАД
             НА КАСКАД ОБНОВЛЕНИЙ
)
ИДТИ
 

Запрос:

 ВЫБЕРИТЕ
    OFFICE.OfficeID
ИЗ
    ОФИС,
    (ВЫБЕРИТЕ СЧЕТ(ИД Агента)
     ОТ АГЕНТА, ОФИС
     ГДЕ OFFICE.OfficeID = АГЕНТ.OfficeID
     ГРУППИРОВАТЬ ПО АГЕНТУ. OfficeID)
СОРТИРОВАТЬ ПО
    OFFICE.OfficeID
 
  • sql-сервер
  • вложенный запрос

1

Я бы сделал это с помощью JOIN и GROUP BY, вложение не требуется и не желательно:

 SELECT o.OfficeID, COUNT(a.AgentID) NumberOfAgents
ИЗ офиса
Агенты LEFT JOIN a ON a.OfficeID = o.OfficeID
ГРУППИРОВАТЬ ПО o.OfficeID
 

Что-то вроде этого (желаемый вывод отсутствует):

 ВЫБЕРИТЕ O.OfficeID
  , (
    ВЫБЕРИТЕ КОЛИЧЕСТВО(*)
    ОТ АГЕНТА А
    ГДЕ A.OfficeID = O.OfficeID
)
ОТ ОФИС О
ЗАКАЗАТЬ ПО O.OfficeID
 

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

0

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