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.
  • Четвертый столбец во внешнем операторе 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.

Использование подзапроса 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.