Select from select t sql: sql — Select * from subquery
Содержание
Пример подзапроса SQL Server
Автор: Rick Dobson |
Комментарии (2) | Похожие: 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | Подробнее > Временные таблицы
Проблема
Подзапрос — это оператор SELECT, встроенный в другой оператор SQL, например
Оператор SELECT, INSERT, DELETE или UPDATE. Набор возвращаемых значений
внутренним оператором SELECT передаются внешнему оператору SQL. Внутренний
Оператор SELECT всегда заключается в круглые скобки. Набор результатов из
внутренний оператор SELECT является примером хранилища временных данных. Подзапросы
может находиться во многих разных местах во внешнем операторе SELECT. Этот
раздел учебника знакомит с темой подзапросов, представляя простые для понимания
примеры кода, демонстрирующие использование подзапросов в предложениях WHERE, списке SELECT
элементы, а также с операторами INSERT, UPDATE и DELETE. Два последующих раздела
детализировать более сложные вопросы, относящиеся к подзапросам.
Решение
Для приведенных ниже примеров мы используем
База данных AdventureWorks2014. Загрузите копию и восстановите на свой экземпляр
SQL Server для тестирования приведенных ниже сценариев.
Использование подзапроса в операторе SQL Server SELECT WHERE Пункт
Одним из наиболее распространенных мест для вызова подзапроса является предложение WHERE
оператор SELECT. Внутренний запрос может исходить из того же источника или из другого источника.
source в качестве внешнего оператора SQL. Когда необходимо вычислить внутренний запрос
для каждой строки внешнего запроса внутренний запрос является коррелированным подзапросом.
В противном случае внутренний запрос является некоррелированным подзапросом. Последующий учебник
Раздел противопоставляет коррелированные и некоррелированные подзапросы.
Внутренний подзапрос в предложении WHERE может возвращать одну или несколько строк. Типичный
использование сравнивает строки набора результатов подзапроса с результатом внешнего запроса SELECT
набор. Результат сравнения определяет, какие строки возвращаются из
внешний запрос с ограничением подзапроса. В этом совете основное внимание будет уделено
основывая сравнения на равенстве (или неравенстве), а также на принадлежности к множеству с использованием
оператор in. Однако существует множество видов операторов для сравнения.
значения столбца внешнего запроса во внутренние возвращаемые значения запроса. Среди них: =, !=, >, >=, <, <= , в, не в, существует, не существует, любой, все.
В приведенном ниже примере кода показано использование подзапроса, возвращающего одно
строка, которая сравнивается с внешней инструкцией SELECT с помощью оператора =. Код
образец использует базу данных Adventureworks2014, которую вы можете скачать по ссылке
выше.
- Подзапрос появляется в конце скрипта в круглых скобках. Этот
очень простой пример возвращает значение ProductCategoryID из ProductCategory
таблицу в производственной схеме. Предложение where в подзапросе
Оператор SELECT определяет, какое значение ProductCategoryID возвращается из
подзапрос. - В приведенном ниже примере возвращенное значение ProductCategoryID из подзапроса
равно 1, но вы можете изменить это значение, изменив предложение WHERE в подзапросе. - Источником внешнего запроса является внутреннее соединение ProductCategory и
Таблицы ProductSubcategory из схемы Production в Adventureworks 2014
база данных.- Две таблицы объединены значениями ProductCategoryID из двух таблиц.
- Внешний запрос может возвращать три столбца данных: ProductCategoryID
и Name из таблицы ProductCategory, а также Name из ProductSubcategory
стол.
- Предложение WHERE во внешнем операторе SELECT сравнивает ProductCategoryID
значения из внешнего оператора SELECT с возвращенным значением ProductCategoryID
из подзапроса. Когда значение ProductCategoryID из внешнего запроса
равно значению ProductCategoryID из подзапроса, то соответствующий
строка из внешнего запроса становится строкой в общем наборе результатов.
-- подзапрос в предложении where, который возвращает 1 строку ВЫБИРАТЬ cat.ProductCategoryID, кот.Имя кот_имя, subcat.Name subcat_name ОТ [AdventureWorks2014].[Production]. [ProductCategory] cat INNER JOIN [AdventureWorks2014].[Production].[ProductSubcategory] subcategory ON cat.ProductCategoryID = subcat.ProductCategoryID ГДЕ cat.ProductCategoryID = -- код в скобках - это подзапрос ( ВЫБЕРИТЕ cat.ProductCategoryID ОТ [AdventureWorks2014].[Production].[ProductCategory] cat ГДЕ cat.ProductCategoryID = 1 )
На следующей вкладке «Результаты» показаны значения, возвращенные предыдущим скриптом.
Обратите внимание, что возвращаются три строки. Все возвращенные строки имеют ProductCategoryID
значение 1, которое соответствует значению ограничения подзапроса. Столбцы в
набор результатов показывает элементы списка выбора во внешнем операторе SELECT с подзапросом
ограничение из предложения WHERE.
Следующий пример подзапроса в предложении WHERE предназначен для подзапроса, возвращающего
более одной строки. Есть несколько способов закодировать такое решение.
Приведенный ниже пример хорошо работает для подзапроса, который возвращает числовые значения, где
порядок числовых значений определяет диапазон значений, которые должны быть возвращены
внешний запрос.
- Первый запрос в следующем скрипте возвращает 37 строк; этот запрос является
внешний запрос без ограничения подзапроса в предложении WHERE. Каждый ряд
для отдельной строки ProductSubcategory. Столбец subcat_name обозначает значения столбца Name из таблицы ProductSubcategory. - Следующий запрос включает ограничение подзапроса для внешнего запроса.
Этот запрос возвращает всего 20 строк. Каждая из этих строк имеет ProductCategoryID.
значение из таблицы ProductCategory 3 или 4. - Ограничение подзапроса разрешает включение всех строк из внешнего
запрос, где значение ProductCategoryID либо- больше или равно 3 и
- меньше или равно 4
- Назначены минимальное и максимальное значения ограничения ProductCategoryID
в операторе объявления для локальных переменных @cat_id_min и @cat_id_max. - Ссылаясь на вывод первого подзапроса без ограничения подзапроса,
вы можете убедиться, что есть восемь строк со значением ProductCategoryID, равным 3.
и дополнительные двенадцать строк со значением ProductCategoryID 4 для общего
из 20 строк ProductSubcategory со значениями ProductCategoryID 3 или более и
меньше или равно 4,
-- внешний запрос без ограничения подзапроса -- запрос возвращает 37 строк ВЫБИРАТЬ cat.ProductCategoryID cat_id, кот.Имя кот_имя, subcat.Name subcat_name ОТ [AdventureWorks2014].[Production].[ProductCategory] cat INNER JOIN [AdventureWorks2014].[Production].[ProductSubcategory] subcategory ON cat.ProductCategoryID = subcat.ProductCategoryID -- подзапрос в предложении where, который может возвращать более 1 строки -- ограничение подзапроса приводит к тому, что внешний запрос возвращает 20 строк -- со значениями ProductCategoryID 3 и 4 ЗАЯВИТЬ @cat_id_min int = 3, @cat_id_max целое = 4 ВЫБИРАТЬ cat.ProductCategoryID cat_id, кот.Имя кот_имя, subcat.Name subcat_name ОТ [AdventureWorks2014].[Production].[ProductCategory] cat INNER JOIN [AdventureWorks2014].[Production]. [ProductSubcategory] subcategory ON cat.ProductCategoryID = subcat.ProductCategoryID ГДЕ cat.ProductCategoryID В -- код в скобках - это подзапрос ( ВЫБЕРИТЕ cat.ProductCategoryID ОТ [AdventureWorks2014].[Production].[ProductCategory] cat ГДЕ cat.ProductCategoryID >= @cat_id_min И cat.ProductCategoryID <= @cat_id_max )
Чтобы прояснить работу кода, два набора результатов из предыдущего
сценарий отображается и описывается.
- Первая вкладка «Результат» показывает набор результатов из запроса без подзапроса
ограничение.- Обратите внимание, что всего 37 строк.
- Также обратите внимание, что есть
- Восемь строк со значением ProductCategoryID 3
- Двенадцать строк со значением ProductCategoryID 4
- На второй вкладке результатов показан набор результатов внешнего запроса с подзапросом.
ограничение.- Для этого набора результатов всего 20 строк.
- Первые восемь строк предназначены для тех, у кого значение ProductCategoryID равно
3. - Следующие двенадцать строк — это строки со значением ProductCategoryID, равным 4.
Когда ограничение подзапроса указывает строковые значения вместо числовых
значений, то вы можете использовать операторы сравнения, которые не требуют чисел.
Следующий синтаксис показывает, как ссылаться на подзапрос из внешнего запроса с помощью
Любой оператор.
- В следующем блоке кода значение поля Name из ProductCategory
таблица с помощью оператора any сравнивается с набором значений имени категории в
подзапрос. - Всякий раз, когда значение столбца Name из таблицы ProductCategory для соединения
таблиц ProductCategory и ProductSubcategory соответствует любой категории
значения имени, возвращенные подзапросом, затем значения поля SELECT для этого
строка из соединения передается в набор результатов для внешнего запроса с подзапросом
ограничение. - Вы можете управлять набором результатов, добавляя и удаляя значения имени категории
из подзапроса. - Поскольку велосипеды и аксессуары перечислены в подзапросе, следующее
блок кода возвращает все строки из объединенных ProductCategory и ProductSubcategory
таблицы со значением столбца «Имя» «Велосипеды» или «Аксессуары» в столбце «Имя»
таблицу ProductCategory.
-- подзапрос в предложении where для подмножества элементов -- продемонстрировать любое операторское приложение ВЫБИРАТЬ cat.ProductCategoryID cat_id, кот.Имя кот_имя, subcat.Name subcat_name ОТ [AdventureWorks2014].[Production].[ProductCategory] cat INNER JOIN [AdventureWorks2014].[Production].[ProductSubcategory] subcategory ON cat.ProductCategoryID = subcat.ProductCategoryID ГДЕ cat.Name = ЛЮБОЙ -- код в скобках - это подзапрос ( ВЫБЕРИТЕ кат.Имя ОТ [AdventureWorks2014].[Production].[ProductCategory] cat ГДЕ кат.Имя В ('Велосипеды', 'Аксессуары') )
На следующей вкладке результатов отображается вкладка результатов предыдущего запроса.
- Все строки в результирующем наборе имеют значение cat_name либо Аксессуары, либо
Велосипеды. Это вытекает из комбинации ограничения подзапроса и
оператор any в предложении WHERE по завершении внешнего запроса. - В результирующем наборе 15 строк:
- Двенадцать со значением cat_name Аксессуары и
- еще три со значением cat_name, равным Bikes
Использование подзапроса в качестве элемента списка SELECT
Примеры кода в этом разделе иллюстрируют два разных подхода к использованию
подзапрос как элемент списка SELECT. Первый пример демонстрирует, как использовать
подзапрос, который возвращает постоянное значение в качестве элемента списка выбора. Второй
пример представляет метод, в котором возвращаемое значение подзапроса может варьироваться в зависимости от
на других элементах списка выбора.
Первый тип запроса называется некоррелированным подзапросом. Это потому что
значение, возвращаемое подзапросом, не зависит от других элементов списка выбора.
Этот некоррелированный элемент списка подзапросов возвращает одно и то же значение для всех строк в
набор результатов.
Следующий блок кода демонстрирует синтаксис для использования некоррелированного подзапроса
как элемент списка выбора. Внешний запрос в следующем блоке кода возвращает
набор результатов с четырьмя столбцами.
- Первые три столбца представляют собой значения полей, основанные на соединении ProductCategory
и таблицы ProductSubcategory. Псевдоним для ProductCategory
table — external_cat, а псевдоним для таблицы ProductSubcategory — subcat.- Первый столбец в результирующем наборе — это поле ProductCategoryID из
таблица ProductCategory; этот столбец имеет псевдоним имени cat_id. - Второй столбец в результирующем наборе — это поле Name из ProductCategory.
стол. Его псевдоним — external_cat_name. - Третий столбец в результирующем наборе — это поле Name из ProductSubcategory.
стол. Его псевдоним — subcat_name.
- Первый столбец в результирующем наборе — это поле ProductCategoryID из
- Четвертый столбец во внешнем операторе SELECT — это подзапрос, который возвращает
одинаковое значение для всех строк. Подзапрос состоит из функции подсчета
для значений ProductSubcategoryID в таблице ProductSubcategory.
псевдоним для этого элемента списка SELECT — total_sub_cat_count.
-- элемент списка выбора на основе некоррелированного подзапроса ВЫБИРАТЬ external_cat.ProductCategoryID cat_id, external_cat.Name external_cat_name, subcat.Name subcat_name, ( ВЫБЕРИТЕ COUNT(ProductSubcategoryID) subcat_id_count ОТ [AdventureWorks2014].[Производство].[Категория_продукта] external_cat INNER JOIN [AdventureWorks2014].[Production].[ProductSubcategory] subcategory ON external_cat.ProductCategoryID = subcat.ProductCategoryID ) total_sub_cat_count ОТ [AdventureWorks2014].[Производство].[Категория_продукта] external_cat INNER JOIN [AdventureWorks2014].[Production].[ProductSubcategory] subcategory ON external_cat.ProductCategoryID = subcat.ProductCategoryID
На следующем изображении вкладки «Результат» показан набор результатов из предыдущего примера кода.
- Первые три столбца получены из объединения ProductCategory
и таблицы ProductSubcategory. - Четвертый столбец имеет одинаковое значение для всех строк. Это значение является
количество значений ProductSubcategoryID в таблице ProductSubcategory.
Значения для четвертого столбца не зависят ни от какого другого значения столбца в
ряд.
Следующий пример кода добавляет новый подзапрос к предыдущему примеру кода.
Этот новый подзапрос демонстрирует синтаксис коррелированного подзапроса, используемого в качестве списка.
элемент.
- Новый подзапрос в приведенном ниже примере кода имеет псевдоним sub_cat_count.
- Подзапрос для этого элемента списка SELECT возвращает количество ProductSubcategoryID
значения в объединении таблиц ProductCategory и ProductSubcategory сгруппированы
по названию категории. - Предложение HAVING в предложении GROUP BY для функции подсчета внутри
подзапрос связывает столбец Name из таблицы ProductCategory для внутреннего
запрос к значению столбца Name из таблицы ProductCategory во внешнем запросе
(имея cat. name = external_cat.Name). - Из-за установки предложения HAVING подзапрос является коррелированным
подзапрос. Корреляция между значениями имени категории из
подзапрос и значения имени категории из внешнего запроса.
-- выберите элементы списка с некоррелированными и коррелированными подзапросами ВЫБИРАТЬ external_cat.ProductCategoryID cat_id, external_cat.Name external_cat_name, subcat.Name subcat_name, ( ВЫБЕРИТЕ COUNT(ProductSubcategoryID) subcat_id_count ОТ [AdventureWorks2014].[Производство].[Категория_продукта] external_cat INNER JOIN [AdventureWorks2014].[Production].[ProductSubcategory] subcategory ON external_cat.ProductCategoryID = subcat.ProductCategoryID ) total_sub_cat_count, ( ВЫБЕРИТЕ COUNT(ProductSubcategoryID) subcat_id_count ОТ [AdventureWorks2014].[Production].[ProductCategory] cat INNER JOIN [AdventureWorks2014].[Production].[ProductSubcategory] subcategory ON cat.ProductCategoryID = subcat. ProductCategoryID СГРУППИРОВАТЬ ПО cat.name ИМЕЕТ cat.name = external_cat.Name ) sub_cat_count ОТ [AdventureWorks2014].[Производство].[Категория_продукта] external_cat INNER JOIN [AdventureWorks2014].[Production].[ProductSubcategory] subcategory ON external_cat.ProductCategoryID = subcat.ProductCategoryID
На следующем снимке экрана показан набор результатов из предыдущего блока кода.
- Первые четыре столбца такие же, как в примере кода для некоррелированного
подзапрос. - Пятый столбец получает свои значения из коррелированного подзапроса с именем sub_cat_count.
Следовательно, пятый столбец в результирующем наборе имеет имя sub_cat_count. - Значения для пятого столбца зависят от имени категории (outer_cat_name) в
внешний запрос. Напротив, все значения для четвертого столбца
то же (37).- Значения, показанные в четвертом столбце, представляют собой общее количество ProductSubcategoryID
значения в объединении таблиц ProductCategory и ProductSubcategory. - Значения, отображающие пятый столбец, являются количеством ProductSubcategoryID
значения внутри каждого значения external_cat_name.
- Значения, показанные в четвертом столбце, представляют собой общее количество ProductSubcategoryID
Использование подзапроса SQL Server для операторов INSERT, UPDATE и DELETE
До этого момента в учебнике демонстрировалось, как использовать подзапросы с
ГДЕ
предложение в операторе SELECT, а также в элементах списка выбора. Это заключение
подраздел о введении подзапросов представляет примеры использования подзапросов в
ВСТАВЛЯТЬ,
Операторы UPDATE и DELETE.
Первая демонстрация предназначена для заполнения локальной временной таблицы массивом
оператор вставки на основе оператора SELECT с подзапросом. Пример кода
ниже начинается с создания новой копии локальной временной таблицы #bikes_subcategories.
В таблице есть три столбца с именами ProductCategoryID, cat_name и subcat_name.
После создания локальной временной таблицы #bikes_subcategories код вызывает
оператор массовой вставки на основе оператора SELECT с подзапросом. Подзапрос
извлекает ProductCategoryID со значением 1 из таблицы ProductCategory
в производственной схеме AdventureWorks2014. Значение ProductCategoryID
1 обозначает категорию велосипедов. Эта категория имеет три подкатегории с именами
горных, шоссейных и туристических велосипедов.
Внешний запрос, ссылающийся на подзапрос, имеет источник, основанный на соединении
Таблицы ProductCategory и ProductSubcategory в базе данных Adventureworks2014.
Элементы списка выбора внешнего запроса включают ProductCategoryID, cat_name из имени
в таблице ProductCategory и subcat_name из столбца Name в
Таблица подкатегорий товаров. Предложение where во внешнем запросе извлекает строки
из объединения, когда их значение ProductCategoryID равно значению, возвращаемому
подзапрос, который равен 1 в примере ниже.
-- создать новую версию таблиц #bikes_subcategories НАЧАТЬ ПОПРОБУЙТЕ --drop table #МужчиныСтуденты --#bikes_subcategories УДАЛИТЬ ТАБЛИЦУ #bikes_subcategories КОНЕЦ ПОПЫТКИ НАЧАТЬ ЛОВИТЬ PRINT '#bikes_subcategories недоступны для сброса' КОНЦЕВОЙ ЗАХВАТ ИДТИ СОЗДАТЬ ТАБЛИЦУ #bikes_subcategories ( ProductCategoryID целое число, cat_name nvarchar(50), subcat_name nvarchar(50) ) -- вставить во временную таблицу из -- оператор select с подзапросом ВСТАВИТЬ В #bikes_subcategories -- подзапрос в предложении where, который возвращает 1 строку ВЫБИРАТЬ cat. ProductCategoryID, кот.Имя кот_имя, subcat.Name subcat_name ОТ [AdventureWorks2014].[Production].[ProductCategory] cat INNER JOIN [AdventureWorks2014].[Production].[ProductSubcategory] subcategory ON cat.ProductCategoryID = subcat.ProductCategoryID ГДЕ cat.ProductCategoryID = -- код в скобках - это подзапрос ( ВЫБЕРИТЕ cat.ProductCategoryID ОТ [AdventureWorks2014].[Production].[ProductCategory] cat ГДЕ cat.ProductCategoryID = 1 ) -- отображать строки, вставленные в #bikes_subcategories ВЫБЕРИТЕ * ИЗ #bikes_subcategories
На следующем снимке экрана показаны три строки, возвращенные оператором SELECT для
все столбцы в локальной временной таблице #bikes_subcategories.
- Все три строки на вкладке «Результаты» ниже имеют значение ProductCategoryID
из 1; это значение, возвращенное подзапросом в предыдущем скрипте. - Значение ProductCategoryID, равное 1, указывает на категорию «Велосипеды».
Поэтому значение столбца cat_name равно Bikes для всех строк в таблице. - В столбце subcat_name отображаются названия подкатегорий для категории «Велосипеды».
Названия подкатегорий: горные велосипеды, шоссейные велосипеды и туристические велосипеды.
В следующем примере кода показано, как использовать подзапрос с оператором UPDATE.
Оператор UPDATE изменяет имя значения подкатегории для строки в таблице.
В следующем примере кода значение Racing Bikes присваивается столбцу subcat_name.
в локальной временной таблице #bikes_subcategories. Ключевое слово UPDATE указывает на
временную таблицу, а оператор set идентифицирует столбец, которому следует назначить Racing
Велосипеды. Ключевое слово where принимает фильтр на основе подзапроса; этот
filter идентифицирует строки, в которых нужно выполнить обновление.
-- изменить subcat_name «Шоссейные велосипеды» на «Гоночные велосипеды». -- subcat_name из #bikes_subcategories ОБНОВЛЕНИЕ #bikes_subcategories SET subcat_name = 'Гоночные велосипеды' ГДЕ subcat_name IN ( ВЫБЕРИТЕ Имя subcat_name ИЗ [AdventureWorks2014]. [Производство].[Подкатегория продукта] ГДЕ [IDКатегорииТоваров] = 1 И Название = «Шоссейные велосипеды» ) -- отображать #bikes_subcategories после обновления ВЫБЕРИТЕ * ИЗ #bikes_subcategories
На следующей вкладке «Результаты» показаны три строки из локальной временной таблицы после
заявление об обновлении. Сравнивая эту вкладку «Результат» с предыдущим результатом
на вкладке вы можете проверить работу оператора UPDATE на основе подзапроса.
Обратите внимание, что вторая строка имеет значение subcat_name для Racing Bikes в следующем
Вкладка «Результат», но значение subcat_name для второй строки — «Шоссейные велосипеды».
Последний пример для этого вводного раздела руководства по подзапросам демонстрирует
использование подзапроса в сочетании с оператором DELETE. Пример кода
ниже удаляет строку из локальной временной таблицы #bikes_subcategories. Подзапрос
обозначает строку для удаления, а ключевое слово DELETE указывает на временную таблицу из
какой удалить строку. Подзапрос указывает строку с subcat_name
стоимость гоночных велосипедов. Оператор DELETE удаляет одну строку в #bikes_subcategories.
локальная временная таблица со значением Racing Bikes.
-- удалить subcat_name "Шоссейные велосипеды" из #bikes_subcategories УДАЛИТЬ #bikes_subcategories ГДЕ subcat_name IN ( SELECT subcat_name ОТ #bikes_subcategories ГДЕ [IDКатегорииТоваров] = 1 AND subcat_name = 'Гоночные велосипеды' ) -- отображать оставшиеся строки #bikes_subcategories ВЫБЕРИТЕ * ИЗ #bikes_subcategories
Вот вкладка «Результаты», которая показывает строки в локальной подкатегории #bikes_subcategories.
временную таблицу после операции оператора удаления. Потому что одна строка
удалены, теперь в таблице две строки вместо трех. Уведомление
это строка со значением subcat_name для Racing Bikes, которая удаляется из
временная таблица.
Следующие шаги
Вот несколько ссылок на ресурсы, которые могут оказаться полезными для развития вашего
понимание содержания из этого раздела учебника.
- Введение в подзапросы в SQL Server
- Подзапрос SQL Server
- Подзапросы SQL
- SQL — подзапросы
- Использование подзапросов в операторе Select
- Вставка записей с помощью подзапросов
- Обновление SQL с использованием подзапросов
- SQL Удаление записей с помощью подзапросов
Об авторе
Рик Добсон — писатель и индивидуальный трейдер. Он также является профессионалом в области SQL Server с многолетним опытом работы с T-SQL, который включает в себя написание книг, проведение национальных семинаров, работу с предприятиями над проектами в области финансов и здравоохранения, а также является постоянным участником MSSQLTips.com. Он оттачивал свои навыки работы с Python в течение более чем пятидесяти лет, особенно для визуализации данных и задач ETL с файлами JSON и CSV. Его последние профессиональные увлечения включают данные и анализ финансовых временных рядов, модели искусственного интеллекта и статистику. Он считает, что правильное применение этих навыков может помочь трейдерам и инвесторам принимать более прибыльные решения.
Посмотреть все мои советы
В этой статье рассматриваются переменные SQL с использованием операторов SET и Select SQL.
SQL Server предоставляет нам два метода в T-SQL для присвоения значения ранее созданной локальной переменной SQL. Первый метод — это оператор SET, стандартный оператор ANSI, который обычно используется для присвоения значения переменной. Второй оператор — это оператор SELECT. В дополнение к своему основному использованию для формирования логики, используемой для извлечения данных из таблицы базы данных или нескольких таблиц в SQL Server, оператор SELECT также может использоваться для присвоения значения ранее созданной локальной переменной напрямую или из переменной. представление или таблица.
Хотя обе инструкции T-SQL выполняют задачу присвоения значения переменной SQL, существует ряд различий между инструкциями SET и SELECT, которые могут привести к тому, что в определенных обстоятельствах вы предпочтете одну из них другой. В этой статье мы подробно опишем, когда и почему следует выбирать между операторами SET и SELECT T-SQL при присвоении значения переменной.
Мы начнем с создания новой таблицы и заполнения ее несколькими записями для нашей демонстрации. Этого можно добиться с помощью следующего скрипта:
1 2 3 4 5 6 7 8 9 9 0003 10 11 12 13 14 15 16 17 | USE SQLShackDemo GO CREATE TABLE SetVsSelectDemo ( ID INT IDENTITY (1,1) PRIMARY KEY, Name NV АРЧАР (50), GroupNumber INT, Grade INT ) GO ВСТАВИТЬ В SetVsSelectDemo VALUES ('Adel',1,350) ВСТАВЬТЕ В ЗНАЧЕНИЯ SetVsSelectDemo («Фейсал», 1 240) ВСТАВЬТЕ В ЗНАЧЕНИЯ SetVsSelectDemo («Худа ',2,180) ВСТАВИТЬ В SetVsSelectDemo VALUES ('Zaid',2,170) ВСТАВИТЬ В SetVsSelectDemo VALUES ('Zaina',3,290) ВСТАВИТЬ В SetVsSelectDemo VALUES ('John ',4,400) ВСТАВИТЬ В ЗНАЧЕНИЯ SetVsSelectDemo ( «Игорь», 4375) |
Вставленные данные можно проверить с помощью следующего оператора SELECT:
ВЫБЕРИТЕ * ИЗ SetVsSelectDemo |
И данные будут показаны ниже:
Если нам удастся присвоить скалярное значение для переменной SQL, которая ранее была определена с помощью оператора DECLARE, оба оператора SET и SELECT достигнут цели в одном и том же способ. Приведенный ниже оператор SET используется для присвоения переменной @EmpName1 скалярного значения «Ali»:
DECLARE @EmpName1 NVARCHAR(50) SET @EmpName1 = 'Али' PRINT @EmpName1 GO |
Таким же образом приведенный ниже оператор SELECT может использоваться для присвоения переменной @EmpName2 скалярного значения «Ali»:
DECLARE @EmpName2 NVARCHAR(50) SELECT @EmpName2 = 'Али' PRINT @EmpName2 ГО |
Назначенные значения для переменных в предыдущих запросах будут напечатаны на вкладке Сообщения, как показано ниже:
SQL Server позволяет нам назначать значение для переменной SQL из таблицы или представления базы данных. Приведенный ниже запрос используется для присвоения переменной @EmpName значения столбца Name третьих членов группы из таблицы SetVsSelectDemo с помощью оператора SET:
DECLARE @EmpName NVARCHAR(50) SET @EmpName = (ВЫБЕРИТЕ [Имя] ИЗ SetVsSelectDemo, ГДЕ GroupNumber = 3) PRINT @EmpName GO |
Оператор SELECT можно также использовать для выполнения той же задачи присваивания другим способом, как показано ниже:
DECLARE @EmpName NVARCHAR(50) SELECT @EmpName = [Name] FROM SetVsSelectDemo WHERE GroupNumber = 3 PRINT @EmpName GO |
Результаты предыдущих двух запросов будут отображаться на вкладке «Сообщения», как показано ниже:
До этого момента вы можете видеть, что операторы SET и SELECT могут одинаково выполнять задачу присвоения значения переменной. и отличаются только со стороны кода.
Несколько переменных SQL
Предположим, что нам нужно присвоить значения нескольким переменным за один раз. Оператор SET может присваивать значение одной переменной за раз; это означает, что если нам нужно присвоить значения двум переменным, нам нужно написать два оператора SET. В приведенном ниже примере для каждой переменной требуется отдельный оператор SET, чтобы присвоить ей скалярное значение перед ее печатью:
1 2 3 4 5 6 | DECLARE @EmpName1 NVARCHAR(50), @EmpName2 NVARCHAR(50) SET @EmpName1 = 'Али' SET @EmpName2 = 'Фади' PRINT @EmpName1 ПЕЧАТЬ @EmpName2 GO |
С другой стороны, оператор SELECT может использоваться для присвоения значений ранее определенным нескольким переменным SQL с помощью одного оператора SELECT. Приведенный ниже оператор SELECT можно легко использовать для присвоения скалярных значений двум переменным с помощью одного оператора SELECT перед его печатью:
DECLARE @EmpName1 NVARCHAR(50) , @EmpName2 NVARCHAR(50) SELECT @EmpName1 = 'Али', @EmpName2 = 'Фади' PRINT @EmpName1 PRINT @EmpName 2 ГО |
Из распечатанного ниже результата видно, что обе инструкции решают одну и ту же задачу, причем инструкция SELECT лучше, чем инструкция SET, при попытке присвоить значения нескольким переменным из-за простоты кода:
Опять же, если мы попытаемся присвоить значения из таблицы базы данных нескольким переменным, это потребует от нас операторов SET, равных количеству переменных. В нашем примере нам нужны два оператора SET для присвоения значений из таблицы SetVsSelectDemo переменным @EmpName и @EmpGrade, как показано в приведенном ниже сценарии:
1 2 3 4 5 6 | DECLARE @EmpName NVARCHAR(50), @EmpGrade INT SET @EmpName = (ВЫБЕРИТЕ [Имя] ИЗ SetVsSelectDemo, ГДЕ GroupNumber = 3) SET @EmpGrade = (ВЫБЕРИТЕ [Уровень] ИЗ SetVsSelectDemo, ГДЕ GroupNumber = 3) PRINT @EmpName PRINT @ EmpGrade GO |
С другой стороны, только один оператор SELECT может использоваться для присвоения значений из таблицы SetVsSelectDemo переменным SQL @EmpName и @EmpGrade с использованием более простого запроса, как показано ниже:
DECLARE @EmpName NVARCHAR(50), @EmpGrade INT SELECT @EmpName=[Name] , @EmpGrade =[Grade] FROM SetVsSelectDemo WHERE GroupNumber = 3 PRINT @EmpName PRINT @EmpGrade GO |
Из предыдущих двух запросов очевидно, что запрос, использующий оператор SELECT, более эффективен, чем запрос, использующий оператор SET, при одновременном присвоении значений нескольким переменным из-за того, что оператор SET может назначать только одну переменную за раз. Аналогичные результаты двух предыдущих запросов, которые выводятся на вкладке «Сообщения», в нашем случае будут такими, как показано ниже:
Несколько значений
Второй момент, в котором проявляется разница между присвоением значений переменным SQL с помощью операторов SELECT или SET, — это когда набор результатов запроса подзапроса, который используется для присвоения значения переменная возвращает более одного значения. В этом случае оператор SET вернет ошибку, так как он принимает только одно скалярное значение из подзапроса, чтобы присвоить его переменной, в то время как оператор SELECT принимает ситуацию, в которой подзапрос вернет несколько значений, не вызывая никакой ошибки. Однако у вас не будет никакого контроля над тем, какое значение будет присвоено переменной, где переменной будет присвоено последнее значение, возвращенное из подзапроса.
Предположим, что нам нужно присвоить значение Name второй группы из ранее созданной таблицы SetVsSelectDemo переменной SQL @EmpName. Напомним, что вторая группа в этой таблице содержит две записи в результирующем наборе, как показано ниже:
Сценарий, который используется для присвоения значения переменной @EmpName из таблицы SetVsSelectDemo с помощью операторов SET и SELECT, будет выглядеть так:
1 2 3 4 5 6 7 8 9 | DECLARE @EmpName NVARCHAR(50) SET @EmpName = (SELECT [Name] FROM SetVsSelectDemo WHERE GroupNumber = 2) PRINT @EmpName GO 90 003 DECLARE @EmpName NVARCHAR(50) SELECT @ EmpName = [Name] FROM SetVsSelectDemo WHERE GroupNumber = 2 PRINT @EmpName GO |
Из-за того, что оператор подзапроса вернул две записи, присвоение значения SQL-переменной @EmpName с помощью оператора SET не удастся, так как оператор SET может присвоить переменным только одно значение. Это не тот случай, когда присваивается значение переменной @EmpName с помощью инструкции SELECT, которая завершится успешно без ошибок, присваивая переменной имя из второй возвращенной записи, то есть «Zaid», как показано в сообщениях результатов ниже:
Из предыдущего результата мы можем узнать, что, когда вы ожидаете, что подзапрос вернет более одного значения, лучше использовать оператор SET для присвоения значения переменной путем реализации надлежащего механизма обработки ошибок, а не используя оператор SELECT, который присвоит последнее возвращенное значение переменной SQL, при этом не будет возвращена ошибка, предупреждающая нас о том, что подзапрос вернул несколько значений.
Не присваивать значения
Другое различие между присвоением значений переменным SQL с помощью операторов SET и SELECT заключается в том, что подзапрос, который используется для присвоения значения переменной, не возвращает никакого значения. Если ранее объявленная переменная не имеет начального значения, операторы SET и SELECT будут действовать одинаково, присваивая этой переменной значение NULL.
Предположим, что нам нужно присвоить переменной @EmpName без начального значения Имя пятой группы из таблицы SetVsSelectDemo. Напомним, что в этой таблице нет записей, относящихся к пятой группе, как показано ниже:
Скрипт, который используется для присвоения значения переменной @EmpName из таблицы SetVsSelectDemo, будет выглядеть так:
1 2 3 4 5 6 7 8 9 9 0003 | DECLARE @EmpName NVARCHAR(50) SET @EmpName = (ВЫБЕРИТЕ [Имя] ИЗ SetVsSelectDemo WHERE GroupNumber = 5) ВЫБЕРИТЕ @EmpName AS SET_Name GO
DECLARE @EmpName NVARCHAR(50) SELECT @EmpName = [Name] FROM SetVsSelectDemo WHERE GroupNumber = 5 SELECT @EmpName AS SELECT_Name ГО |
При отсутствии начального значения для переменной @EmpName и отсутствии значения, возвращаемого из подзапроса, этой переменной будет присвоено значение NULL в обоих случаях, как ясно показано в сообщении результата ниже:
Если ранее объявленное Переменная SQL имеет начальное значение, а подзапрос, который используется для присвоения значения переменной, не возвращает никакого значения, оператор SET и SELECT будут вести себя по-разному. В этом случае оператор SET переопределит начальное значение переменной и вернет значение NULL. Напротив, оператор SELECT не переопределит начальное значение переменной и вернет его, если значение не возвращается из присваивающего подзапроса.
Если мы снова присвоим переменной @EmpName Имя пятой группы из таблицы SetVsSelectDemo, напомнив, что в этой таблице нет записей, принадлежащих пятой группе, но на этот раз, после установки начального значения для @ Переменная SQL EmpName во время объявления переменной с использованием операторов SET и SELECT, как показано в приведенном ниже сценарии:
1 2 3 4 5 6 7 8 9 | DECLARE @EmpName NVARCHAR(50)='Sanya' SET @EmpName = (SELECT [Name] FROM SetVsSelectDemo WHERE GroupNumber = 5) SELECT @EmpName AS SET_Name GO
DECLARE @EmpName NVARCHAR( 50)='Саня' ВЫБЕРИТЕ @EmpName = [Имя] ИЗ SetVsSelectDemo WHERE GroupNumber = 5 ВЫБЕРИТЕ @EmpName КАК SELECT_Name ПЕРЕЙТИ |
Принимая во внимание, что присваивающий подзапрос не вернул значение, запрос, в котором использовалась инструкция SET для присвоения значения переменной SQL, переопределит начальное значение переменной, возвращая значение NULL, в то время как запрос, в котором использовалась инструкция SELECT для присвоение значения переменной сохранит начальное значение без изменений, поскольку значение не возвращается из подзапроса, как ясно показано в результатах ниже:
Заключение
SQL Server предоставляет нам два основных метода, которые используются для присвоения значений переменным SQL. В большинстве случаев операторы SET и SELECT без проблем выполняют задачу присвоения значения переменной. В некоторых ситуациях вы можете предпочесть использовать один вместо другого, например:
- Если вам удается присвоить значения нескольким переменным напрямую или из таблицы базы данных, лучше использовать оператор SELECT, для которого требуется только один оператор, над оператором SET из-за простоты кодирования
- Если вы следуете стандарту ANSI для миграции кода, используйте оператор SET для назначения значений переменных SQL, так как оператор SELECT не соответствует стандарту ANSI
- Если присваивающий подзапрос возвращает несколько значений, использование оператора SET для присвоения значения переменной вызовет ошибку, поскольку он принимает только одно значение, где оператор SELECT присвоит переменной последнее значение, возвращенное из подзапроса, без контроль с вашей стороны
- Если присваивающий подзапрос не возвращает никакого значения, инструкция SET заменит начальное значение переменной на NULL, в то время как инструкция SELECT не заменит ее начальное значение
- Автор
- Последние сообщения
Ахмад Ясин
Ахмад Ясин — инженер Microsoft по работе с большими данными, обладающий глубокими знаниями и опытом в области SQL BI, администрирования и разработки баз данных SQL Server.