Відмінності між операторами 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.