Sql вложенные запросы select: Вложенные SQL запросы
Содержание
Вложенные запросы SQL — CodeTown.ru
Здравствуйте, уважаемые читатели! В этой статье мы поговорим о том, что такое вложенные запросы в SQL. Традиционно, рассмотрим несколько примеров с той базой данных, которую создавали в первых статьях.
Введение
Итак, само название говорит о том, что запрос во что-то вложен. Так вот, вложенный запрос в SQL означает, что запрос select выполняется в еще одном запросе select — на самом деле вложенность может быть и многоуровневой, то есть select в select в select и т.д.
Такие запросы обычно используются для получения данных из двух и более таблиц. Они нужны чтобы данные из разных таблиц можно было соотнести и по зависимости осуществить выборку. У вложенных запросов есть и недостаток — зачастую слишком долгое время работы занимает запрос, потому что идет большая нагрузка на сервер. Тем не менее, саму конструкцию необходимо знать и использовать при возможности.
Структура ранее созданных таблиц
Прежде чем перейдем к простому примеру, напомним структуру наших таблиц, с которыми будем работать:
- Таблица Salespeople (продавцы):
snum | sname | city | comm |
---|---|---|---|
1 | Колованов | Москва | 10 |
2 | Петров | Тверь | 25 |
3 | Плотников | Москва | 22 |
4 | Кучеров | Санкт-Петербург | 28 |
5 | Малкин | Санкт-Петербург | 18 |
6 | Шипачев | Челябинск | 30 |
7 | Мозякин | Одинцово | 25 |
8 | Проворов | Москва | 25 |
- Таблица Customers (покупатели):
сnum | сname | city | rating | snum |
---|---|---|---|---|
1 | Деснов | Москва | 90 | 6 |
2 | Краснов | Москва | 95 | 7 |
3 | Кириллов | Тверь | 96 | 3 |
4 | Ермолаев | Обнинск | 98 | 3 |
5 | Колесников | Серпухов | 98 | 5 |
6 | Пушкин | Челябинск | 90 | 4 |
7 | Лермонтов | Одинцово | 85 | 1 |
8 | Белый | Москва | 89 | 3 |
9 | Чудинов | Москва | 96 | 2 |
10 | Лосев | Одинцово | 93 | 8 |
- Таблица Orders (заказы)
onum | amt | odate | cnum | snum |
---|---|---|---|---|
1001 | 128 | 2016-01-01 | 9 | 4 |
1002 | 1800 | 2016-04-10 | 10 | 7 |
1003 | 348 | 2017-04-08 | 2 | 1 |
1004 | 500 | 2016-06-07 | 3 | 3 |
1005 | 499 | 2017-12-04 | 5 | 4 |
1006 | 320 | 2016-03-03 | 5 | 4 |
1007 | 80 | 2017-09-02 | 7 | 1 |
1008 | 780 | 2016-03-07 | 1 | 3 |
1009 | 560 | 2017-10-07 | 3 | 7 |
1010 | 900 | 2016-01-08 | 6 | 8 |
Основы вложенных запросов в SQL
Вывести сумму заказов и дату, которые проводил продавец с фамилией Колованов.
Начнем с такого примера и для начала вспомним, как бы делали этот запрос ранее: посмотрели бы в таблицу Salespeople, определили бы snum продавца Колыванова — он равен 1. И выполнили бы запрос SQL с помощью условия WHERE. Вот пример такого SQL запроса:
SELECT amt, odate FROM orders WHERE snum = 1
Очевидно, какой будет вывод:
amt | odate |
---|---|
348 | 2017-04-08 |
80 | 2017-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 выдаст фамилию этого продавца.
Получился такой результат:
snum | sname |
---|---|
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
title | description | author | ms. service | ms.subservice | ms.topic | ms.date | ms.author | ms.openlocfilehash | ms.sourcegitcommit | ms.translationtype | ms.contentlocale | ms.lasthandoff | ms.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-09 | Gram |
μг | микрограм | 1,00 e-06 | Gram |
mg | миллиграм | 1,00 e-03 | Gram |
н | Gram | 1,00 e + 00 | Gram |
кг | Килограмм | 1,00 e + 03 | Gram |
MG | мегаграм | 1,00 e + 06 | Gram |
GG | гигаграм | 1,00 e + 09 | Gram |
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.