Dynamic SQL is just like it sounds: creating a SQL statement dynamically.

A normal SQL Statement is just the string you are going to run.

SELECT FIELD1, FIELD2, FIELD3 FROM TABLE1;

But should you have a good business reason to do so, maybe you want to dynamically create the queries. (Personally, Dynamic SQL is the last solution I would do.)

DECLARE @SqlString NVARCHAR(1000),
@ColName NVARCHAR(30) = ‘Field1’
@TableName NVARCHAR(30) = ‘Table1’ ;

SET @SqlString = ‘SELECT ‘ + @ColName + ‘ FROM ‘ + @TableName;
SELECT @SqlString;

The result for that query is going to show: “SELECT Field1 FROM Table1”

You have the string you want to run, but how do you run it? There are a couple of ways.

EXECUTE

Execute will let you run a Dynamic SQL Statement.

Two things it won’t do:

  • Keep any kind of execution plan for running the query
  • Pass values out of it.
CREATE TABLE TMP (TmpId INT IDENTITY(1,1), TmpVal NVARCHAR(10));

INSERT INTO TMP (TmpVal) VALUES
('A'),
('B'),
('C');

DECLARE @SqlString NVARCHAR(1000),
                   @ColName NVARCHAR(30) = 'TmpVal', 
                  @TableName NVARCHAR(30) = 'Tmp';

--MAKE A SELECT STATEMENT
SET @SqlString = 'SELECT ' + @ColName + ' FROM ' + @TableName;
SELECT @SqlString AS SelectExample;  
EXECUTE (@SqlString);

--MAKE A SELECT STATEMENT WITH TOP 1
SET @SqlString = 'SELECT TOP 1 ' + @ColName + ' FROM ' + @TableName;
SELECT @SqlString AS TmpValTop1;
EXECUTE (@SqlString);

--MAKE A SELECT STATEMENT WITH A 
SET @SqlString = 'SELECT MAX(' + @ColName
   + ') MaxTmpVal FROM ' + @TableName;
SELECT @SqlString AS MaxTmpVal;
EXECUTE (@SqlString);

SET @SqlString = 'UPDATE ' + @TableName 
  + ' SET TmpVal = ''D'' WHERE ' + @ColName + '=''C''';
SELECT @SqlString AS UpdateExample;
EXECUTE (@SqlString);

SET @SqlString = 'INSERT INTO ' + @TableName + ' (TmpVal) VALUES (''C'')';
SELECT @SqlString AS InsertExample;
EXECUTE (@SqlString);

SELECT * FROM TMP;

DROP TABLE Tmp;

SP_EXECUTESQL

sp_ExecuteSQL will allow you to pass variable values into and out of the SQL string you create with Dynamic SQL. It may also save an execution plan.

--TEST DATA--
create table dates (DateId int identity(1,1), DateVal datetime);

insert into dates (DateVal) values
('2017-01-05'),
('2017-01-06'),
('2017-01-07'),
('2017-01-08')
--SHOW THE VALUE IT SHOULD BE
select min(DateVal) AS TestMinVal from dates;

DECLARE @MinDateVal DATETIME;

SELECT @MinDateVal = min(DateVal) FROM dates;

--SHOW THE VALUE USING THE VARIABLE THAT IT STORES
SELECT @MinDateVal MinDateValSet;
--SET TO NULL TO PROVE WE'RE NOT CHEATING :P
SET @MinDateVal = NULL;

--NOTHING UP MY SLEEVE, AND....
SELECT @MinDateVal AS SetToNull;

--THE SQLSTRING WILL BE THE ACTUAL SQL THAT IS EXECUTED.
DECLARE @SqlString NVARCHAR(1000), 
        @ColName NVARCHAR(30) = 'DateVal', 
        @TableName NVARCHAR(30) = 'dates';
--CREATING THE SQL STRING
SET @SqlString = 'SELECT @MinDateVal = MIN(' 
    + @ColName 
    + ') FROM ' + @TableName;

--THIS SHOWS WHAT WILL BE RAN
SELECT @SqlString AS SqlString;
--USING THIS, WE CAN SPECIFY THE MINDATEVAL VARIABLE 
--AND HAVE THE VALUE PASSED OUT FROM THE DYNAMIC SQL
EXECUTE sp_executesql @SqlString 
     , N'@MinDateVal DATETIME OUTPUT' 
     , @MinDateVal = @MinDateVal OUTPUT;
SELECT @MinDateVal;