Storing a variable with a SELECT, and why it didn't work.

, 2018-04-02

One of the ways to set the value of a variable is with a SELECT statement. This has the benefit of being able to set multiple variables at once.

DECLARE @create_date datetime = '1/1/1900'
DECLARE @database_id int = 0
SELECT @create_date = create_date, 
     @database_id = database_id
FROM sys.databases
WHERE name = 'master'
SELECT @create_date AS Create_Date, @database_id AS Database_Id

This is a very useful technique but you do have to be careful. What happens can vary depending on the number of rows you get back from the query.

One row

This is the best case and will act exactly like you expect. The value for each variable will be the specified values from the row returned.

Multiple rows

If you have multiple rows being returned then the values stored in the variables will be from the <em>last</em> row returned from the query.  

DECLARE @create_date datetime = '1/1/1900'
DECLARE @database_id int = 0
SELECT @create_date = create_date, 
     @database_id = database_id
FROM sys.databases
SELECT @create_date AS Create_Date, @database_id AS Database_Id

The problem here is that last is pretty uncertain unless you put an ORDER BY into the query. Remember that without an ORDER BY, a query has no guaranteed order. It might be in the same order hundreds of times and then change for some reason (a new index was added, SQL was updated, or something even less obvious).

No rows

This one can get really confusing if you aren't aware it can happen. If your query returns no rows then the variables will remain unchanged.

DECLARE @create_date datetime = '1/1/1900'
DECLARE @database_id int = 0
SELECT @create_date = create_date, 
     @database_id = database_id
FROM sys.databases
WHERE 1=0
SELECT @create_date AS Create_Date, @database_id AS Database_Id

You might think that you could change the query to use ISNULL to avoid the problem:

SELECT @create_date = ISNULL(create_date,'12/31/2099'), 
@database_id = ISNULL(database_id,-1)
FROM sys.databases
WHERE 1=0

But this doesn't help. The problem is that without any rows being returned no update will happen. Putting an ISNULL around the result (or any other functions you try to use) will only make a difference if a row is actually being returned. There best way to avoid this particular problem is to initializing your variables ahead of time. Also if you are resetting the variable multiple times make sure that you reinitialize it within each code block. For example:

DECLARE @create_date datetime = '1/1/1900'
DECLARE @database_id int = 0
SELECT @create_date = create_date, 
     @database_id = database_id
FROM sys.databases
WHERE name = 'master'
/* Code goes here */
SET @create_date = '1/1/1900'
SET @database_id = 0
SELECT @create_date = create_date, 
     @database_id = database_id
FROM sys.databases
WHERE name = 'SSISDB'
/* Code goes here */

In the code above I'm pulling the information for master, then I'm doing some processing on that information. Next, I'm pulling information about SSISDB and processing it. If I don't reinitialize the variables and don't happen to have an SSISDB then I'm going to reprocess master.

Using SELECT to store values into a variable is something you will have to know how to do if you are doing much coding in T-SQL. But you also have to know how it reacts and how to avoid problems.

Rate

3.9 (21)

Share

Share

Rate

3.9 (21)

Related content

A Normalization Primer

For most DBAs, normalization is an understood concept, a bread and butter bit of knowledge. However, it is not at all unusual to review a database design by a development group for an OLTP (OnLine Transaction Processing) environment and find that the schema chosen is anything but properly normalized. This article by Brian Kelley will give you the core knowledge to data model.

5 (3)

2003-01-13

17,240 reads