Відмінності між операторами SET та SELECT при присвоюванні значень змінним, Олонцев Сергій

Блог про обробку та аналіз даних

Відмінності між операторами SET та SELECT при присвоюванні значень змінним

У SQL Server в мові T-SQL є два оператори SET і SELECT, і вони обидва можуть використовуватися для надання значень змінним. У деяких ситуаціях використання того чи іншого оператора може призвести до несподіваних та непередбачуваних результатів. У цій статті я хотів би детально розглянути відмінності між ними і розповісти про різні пастки, в які ви можете потрапити.

В першу чергу обидва оператори можуть рівнозначно використовуватися для присвоєння фіксованих значень змінних. Однак, оператор SET є стандартом для мови SQL, в той час як SELECT є особливістю тільки T-SQL діалекту SQL Server.

declare @int_example int, @dt_example datetime, @str_example varchar(255); set @int_example = 1; set @dt_example = getdate(); set @str_example = 'qwe'; select @int_example, @dt_example, @str_example; select @int_example = 1; select @dt_example = getdate(); select @str_example = 'qwe'; select @int_example, @dt_example, @str_example; go

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

declare @int_example int, @dt_example datetime, @str_example varchar(255); select @int_example = 1, @dt_example = getdate(), @str_example = 'qwe'; select @int_example, @dt_example, @str_example; go

Якщо ми спробуємо використовувати у цій ситуації SET, то отримаємо помилку, т.к. він просто не підтримує такої операції.

declare @int_example int, @dt_example datetime, @str_example varchar(255); set @int_example = 1, @dt_example = getdate(), @str_example = 'qwe'; select @int_example,@dt_example, @str_example; go

Msg 102, Level 15, State 1, Line 7Incorrect syntax near ‘,’.

Також обидва оператори можуть застосовуватися для присвоєння значень змінним таблиці. Однак, якщо SELECT можна використовувати безпосередньо, то у випадку з SET доведеться все одно використовувати SELECT, щоб отримати вибірку з таблиці, і вже намагатись її результати присвоїти змінній.

create table #tmp (>

Єдине, необхідно враховувати, що якщо результат запиту до таблиці поверне більше одного значення, то у випадку з операцією SET ми отримаємо помилку.

create table #tmp (>

Msg 512, Level 16, State 1, Line 25Subquery returned more than 1 value. Це не дозволяється, коли subquery follows =, !=, , >= or when the subquery is used as an expression.

У випадку використання оператора SELECT помилки не виникне, але в загальному випадку ми не можемо точно передбачити, яке з значень, що задовольняють умові вибірки, буде присвоєно змінною. Розглянемо перший випадок, коли запит поверне 32.

create table #tmp (>

У наступному випадку, запит повертає 31.

create table #tmp (>

Як ми змогли переконатися, недетермінованість вибірки може призводити до несподіваних результатів. Тому в даному випадку я рекомендував би використовувати оператор SET, щоб як мінімум отримати помилку, а також стежити за умовами вибірки, щоб не допускати подібних ситуацій. І ще один момент, на якому я хотів би зупинитися, коли під умови вибірки не потрапляє жодного запису і при цьому значення змінної вже ініціалізоване будь-яким значенням.

create table #tmp (>

Як ми можемо легко переконатися, оператор SET присвоїв значення змінної NULL, аОсь оператор SELECT просто проігнорував привласнення і залишив значення змінної таким, яким воно було цієї спроби. В результаті, якщо ми будемо використовувати оператор SELECT, ми не можемо точно знати, чи було проініціалізоване значення змінної чи ні. Як варіант ми можемо перевіряти значення змінної @@rowcount, яке дорівнюватиме нулю, якщо оператор SELECT не знайшов жодного запису, що підходить під умову та ініціалізації не відбулося.

create table #tmp (>

Підіб'ємо підсумки, ви можете використовувати обидва оператори, але повинні чітко розуміти, в якій ситуації і що від них очікувати. Використовуйте оператор SET, якщо:

  • Якщо ви надаєте фіксовані значення змінним без використання запитів і хочете дотримуватися стандартів.
  • Очікуєте, що змінній буде надано значення NULL, якщо запит не повернув жодних результатів.
  • Запит може повернути кілька значень і ви хочете відстежувати такі ситуації.

І використовуйте оператор SELECT, якщо:

  • Хочете за одну інструкцію присвоїти значення відразу декільком змінним.
  • У разі вибірки значення з таблиці готові контролювати, чи справді відбулася ініціалізація, наприклад, за допомогою @@rowcount.