SQL Clone
SQLServerCentral is supported by Redgate
 
Log in  ::  Register  ::  Not logged in
 
 
 

A Simple Introduction to Dynamic SQL

By Paulo de Jesus,

Introduction

Quite often you do not know what values or parameters will be required, and writing many conditional clauses to cater for the possible variations is not only time consuming and difficult to maintain, but very inefficient as well. As the name suggests, Dynamic SQL allows you to write SQL code dynamically because certain sections of the code will only be known at run-time. The mere mention of Dynamic SQL makes some people a bit scared, but it is actually quite simple once you get your head around it. Dynamic SQL is essentially normal SQL written in such a way that you end up with a “customised” SQL script at run-time.

Basic Concatenation and Explicit Conversions

Before we get started we need to understand the basics of how strings are concatenated in SQL. Let’s look at the following script:

DECLARE @NoOfColumns AS SMALLINT
SET @NoOfColumns = 3
DECLARE @Result1 AS VARCHAR(100)
DECLARE @Result2 AS VARCHAR(100)

SELECT @Result1 = 'Total of ' + CAST(@NoOfColumns AS VARCHAR) + ' column(s)'
SELECT @Result1

SELECT @Result2 = CONCAT('Total of ', CAST(@NoOfColumns AS VARCHAR), ' column(s)')
SELECT @Result2

Result1:

Result2:

Both of the SELECT statements can be used to concatenate the separate parts and return the same result, by either using the + operator or the CONCAT function. Please note that the CAST function is used explicitly change the data type because you can’t implicitly concatenate a non-alphanumeric data type into an alphanumeric data type. You could also use the CONVERT function to do this.

If you run the following script and do not explicitly change the data type you will receive an error:

DECLARE @NoOfColumns AS SMALLINT
SET @NoOfColumns = 3
DECLARE @Result1 AS VARCHAR(100)

SELECT @Result1 = 'Total of ' + @NoOfColumns + ' column(s)'
SELECT @Result1

Result1:

For more on implicit and explicit conversions have a look at: https://www.brentozar.com/archive/2016/05/implicit-vs-explicit-conversion/

For the differences between CAST and CONVERT have a look at: https://blog.teamsql.io/cast-vs-convert-714583582566

Escaping a Single Quote in a String

Concatenating a string is very simple, but what happens if we want the result to include quote marks around the number? Let’s look at the following script:

DECLARE @NoOfColumns AS SMALLINT
SET @NoOfColumns = 3
DECLARE @Result AS VARCHAR(100)

SELECT @Result = 'Total of '' + CAST(@NoOfColumns AS VARCHAR) + '' column(s)'
SELECT @Result

Result:

As you can see, you can’t simply add the single quotes into your string because the new single quote escapes the second one, leaving your string declaration open until the very last single quote at the end. Everything in between is treated as text. A good clue that this is happening is when functional parts of your script change to the same colour as text.

The correct syntax would be to add two single quotes in your string as follows:

DECLARE @NoOfColumns AS SMALLINT
SET @NoOfColumns = 3
DECLARE @Result AS VARCHAR(100)

SELECT @Result = 'Total of ''' + CAST(@NoOfColumns AS VARCHAR) + ''' column(s)'
SELECT @Result

Result:

Looking only at the first section of the string ('Total of ''') for example:

  • - The first quote opens the string declaration
  • - The second quote tells SQL that the next quote should be included in the string
  • - The third quote is that one that is included in the string
  • - The fourth quote closes the string declaration

Writing and Executing Dynamic SQL

Now let’s combine what we’ve learnt and write some Dynamic SQL. For arguments sake, let’s say that we have a SQL instance which contains multiple databases that all have the exact same schema.

If you wanted to do a count of how many rows were inserted today in a particular table by only changing the database name, you could write something like this:

DECLARE @DBName AS VARCHAR(20)
SET @DBName = 'Branch1'
DECLARE @Date AS DATE
SET @Date = GETDATE()
DECLARE @SQL AS VARCHAR(2000)

SELECT @SQL =
'SELECT COUNT(1) ' +
'FROM [' + @DBName + '].[dbo].[CommonTable] ' +
'WHERE [InsertDate] = ''' + CAST(@Date AS VARCHAR) + ''''

PRINT @SQL
EXEC (@SQL)

The EXEC statement will execute the T-SQL code that you have generated dynamically.

This is obviously just a silly example but it shows the basic structure of how you dynamically create your T-SQL code and execute it. Realistically the database name would be passed as a parameter in a stored procedure, but please see the important note lower down.

Debugging Tip

As you will see in the code example above, before executing anything, make use of the PRINT statement when testing your code to see what the result of the concatenations looks like. If you’re using SQL Management Studio, select the “Results” tab at the bottom, copy the PRINT text result from there and paste it into a new query window. This way you will be able to clearly see if you are getting the correct syntax.

The PRINT above will output the following T-SQL:

A Very Important Note

When placing your Dynamic SQL code into production (typically in stored procedures), be careful about concatenating alphanumeric parameters directly because of SQL injection.

For more information on SQL injection have a look at: https://docs.microsoft.com/en-us/sql/relational-databases/security/sql-injection

Conclusion

As you have seen Dynamic SQL isn’t so difficult as long as you keep in mind what you want your final script to look like. The PRINT statement is your friend and it is important to remember about SQL injection when working with parameters and Dynamic SQL.

 
Total article views: 1430 | Views in the last 30 days: 10
 
Related Articles
FORUM

How to declare parameters inside "select"?

select asset.asset_name asset_name (varchar(100))?

FORUM

Different behaviour of SQL Server when setting varchar size

When declaring parameters of varchar, setting size gives different query results

FORUM

Tricky ...VARCHAR

VARCHAR logics

FORUM

Different Behaviour of VARCHAR and NVARCHAR

Variables declared with VARCHAR and NVARCHAR were behaviouring differently.

FORUM

Difference between varchar(max) and varchar(8000)

Difference between varchar(max) and varchar(8000)

 
Contribute