SQLUSA
BI TRIO 2008
FREE TRIAL
CLICK HERE TO ORDER

SQL Server 2008 Best Practices
SQL Server 2005 Best Practices

How to build and execute dynamic SQL queries?

Execute the following Microsoft SQL Server T-SQL example scripts in Management Studio Query Editor to demonstrate the building and execution of dynamic SQL queries. The dynamic SQL query is executed in a child process.

------------

-- Dynamic SQL 101 - QUICK SYNTAX

------------

USE AdventureWorks2008;

EXEC ('SELECT * FROM Production.Product')

 

DECLARE @SQL varchar(256); SET @SQL='SELECT * FROM Production.Product'

EXEC (@SQL)

 

DECLARE @SQL varchar(256), @Table sysname;

SET @SQL='SELECT * FROM'; SET @Table = 'Production.Product'

SET @SQL = @SQL+' '+@Table

PRINT @SQL  -- for debugging

EXEC (@SQL) -- Dynamic SQL execution

 

-- Dynamic SQL for rowcount in all tables

DECLARE @SQL nvarchar(max), @Schema sysname, @Table sysname;

SET @SQL = ''

SELECT @SQL = @SQL + 'SELECT '''+QUOTENAME(TABLE_SCHEMA)+'.'+

  QUOTENAME(TABLE_NAME)+''''+

  '= COUNT(*) FROM '+ QUOTENAME(TABLE_SCHEMA)+'.'+QUOTENAME(TABLE_NAME) +';'

FROM INFORMATION_SCHEMA.TABLES WHERE TABLE_TYPE='BASE TABLE'

PRINT @SQL -- test & debug

EXEC sp_executesql @SQL

 

-- Equivalent code with the undocumented sp_MSforeachtable

EXEC sp_MSforeachtable 'select ''?'', count(*) from ?'
------------

-- FIRST EXAMPLE - dynamic SQL stored procedure for customer list

USE Northwind;

GO

IF EXISTS (SELECT *

           FROM   sys.objects

           WHERE  object_id = Object_id(N'[dbo].[CustomerListByState]')

                  AND TYPE IN (N'P',N'PC'))

  DROP PROCEDURE [dbo].[CustomerListByState]

GO

 

-- Dynamic SQL stored procedure

CREATE PROCEDURE CustomerListByState

                @States VARCHAR(128)

AS

  BEGIN

    DECLARE  @SQL NVARCHAR(1024)

    SET @SQL = 'select CustomerID, CompanyName, ContactName, Phone,

                        Region from Customers where Region

                        IN (' + @States + ')' + ' order by Region'

    PRINT @SQL -- For testing and debugging

/* The following query is executed as dynamic SQL

select CustomerID, CompanyName, ContactName, Phone, Region

   from Customers where Region IN ('WA', 'OR', 'ID', 'CA') order by Region

*/

 

    -- Dynamic SQL execution

    EXEC Sp_executesql  @SQL

  END

GO

 

-- Execute dynamic SQL stored procedure

DECLARE  @States VARCHAR(100)

SET @States = '''WA'', ''OR'', ''ID'', ''CA'''

EXEC CustomerListByState   @States

GO

/* Partial results

 

CustomerID  CompanyName                   ContactName       Phone           Region

LETSS       Let's Stop N Shop             Jaime Yorres      (415) 555-5938  CA

SAVEA       Save-a-lot Markets            Jose Pavarotti    (208) 555-8097  ID

GREAL       Great Lakes Food Market       Howard Snyder     (503) 555-7555  OR

HUNGC       Hungry Coyote Import Store    Yoshi Latimer     (503) 555-6874  OR

*/

 

/* QUOTENAME can also be used to build sproc execution string

 

DECLARE @States VARCHAR(100)

SET @States = QUOTENAME('WA','''')+','+ QUOTENAME('OR','''')

EXEC CustomerListByState @States

GO

*/

------------

 

-- SECOND EXAMPLE - make TABLESAMPLE dynamic

 

-- Dynamic SQL for TABLESAMPLE

-- T-SQL dynamic sql

-- SQL tablesample

DECLARE @Size tinyint = 7

DECLARE @SQL nvarchar(512) =

    'SELECT PurchaseOrderID, OrderDate = CAST(OrderDate AS DATE),

     VendorID FROM AdventureWorks2008.Purchasing.PurchaseOrderHeader

       TABLESAMPLE ('+ CAST(@Size AS VARCHAR)+' PERCENT)'

PRINT @SQL -- for testing & debugging purposes

/*

SELECT PurchaseOrderID, OrderDate = CAST(OrderDate AS DATE),

     VendorID FROM AdventureWorks2008.Purchasing.PurchaseOrderHeader

       TABLESAMPLE (7 PERCENT)

*/

-- SQL Server execute dynamic sql

EXEC sp_executesql @SQL

GO

-- (435 row(s) affected)

/* Partial results

 

PurchaseOrderID   OrderDate   VendorID

349               2003-06-23  1672

350               2003-06-23  1600

351               2003-06-23  1522

352               2003-06-23  1570

353               2003-06-23  1516

*/

------------

 

-- THIRD EXAMPLE - dynamic SQL execution with parameters

 

-- Dynamic SQL script - SQL Server 2008

-- Communicating with child process using command line parameters

-- sp_executesql parameter usage

USE AdventureWorks2008;

DECLARE  @ParmDefinition NVARCHAR(1024) = N'@FirstLetterOfLastName char(1),

      @LastFirstNameOUT nvarchar(50) OUTPUT'

DECLARE @FirstLetter CHAR(1) = 'P', @LastFirstName NVARCHAR(50)

DECLARE @SQL NVARCHAR(MAX) = N'SELECT @LastFirstNameOUT = max(FirstName)

      FROM Person.Person'+CHAR(13)+

      'WHERE left(LastName,1) = @FirstLetterOfLastName'

PRINT @SQL+CHAR(13) -- For testing and debugging

/*

SELECT @LastFirstNameOUT = max(FirstName)

FROM Person.Person

WHERE left(LastName,1) = @FirstLetterOfLastName

*/

PRINT @ParmDefinition -- For testing and debugging

/*

@FirstLetterOfLastName char(1),

@LastFirstNameOUT nvarchar(50) OUTPUT

*/

EXECUTE sp_executeSQL

      @SQL,

      @ParmDefinition,

      @FirstLetterOfLastName = @FirstLetter,

      @LastFirstNameOUT=@LastFirstName OUTPUT

 

SELECT

[Last First Name] = @LastFirstName,

Legend='of last names starting with',

Letter=@FirstLetter

GO

------------

 

-- FOURTH EXAMPLE - enumerate all objects in databases


-- Return objects count in all databases on the server

-- Dynamic SQL stored procedure

-- SQL quotename used to build valid db object names

USE AdventureWorks;

GO

IF EXISTS (SELECT *

           FROM   sys.objects

           WHERE  object_id = Object_id(N'[dbo].[sprocObjectCountsAllDBs]')

                  AND TYPE IN (N'P',N'PC'))

  DROP PROCEDURE [dbo].[sprocObjectCountsAllDBs]

GO

CREATE PROC sprocObjectCountsAllDBs

AS

  BEGIN

    DECLARE  @dbName      SYSNAME,

             @ObjectCount INT

    DECLARE  @SQL NVARCHAR(MAX)

    DECLARE  @DBObjectStats  TABLE(

                                   DBName    SYSNAME,

                                   DBObjects INT

                                   )

    DECLARE curAllDBs CURSOR  FOR

    SELECT   name

    FROM     MASTER.dbo.sysdatabases

    WHERE    name NOT IN ('master','tempdb','model','msdb')

    ORDER BY name

    OPEN curAllDBs

    FETCH  curAllDBs

    INTO @dbName

  

    WHILE (@@FETCH_STATUS = 0) -- loop through all db-s

      BEGIN

        -- Build valid yet hard-wired SQL statement

        -- SQL QUOTENAME is used for valid identifier formation

        SET @SQL = 'select @dbObjects = count(*)' + Char(13) + 'from ' + Quotename(@dbName) + '.dbo.sysobjects'

        

        PRINT @SQL -- Use it for debugging

        

        -- Dynamic SQL call with output parameter(s)

        EXEC Sp_executesql

          @SQL ,

          N'@dbObjects int output' ,

          @dbObjects = @ObjectCount OUTPUT

        

        INSERT @DBObjectStats

        SELECT @dbName,  @ObjectCount

        

        FETCH  curAllDBs INTO @dbName

      END -- while

    CLOSE curAllDBs

    DEALLOCATE curAllDBs

    -- Return results

    SELECT *

    FROM   @DBObjectStats

  END

GO

 

-- Execute stored procedure with dynamic SQL

EXEC sprocObjectCountsAllDBs

GO

------------

-- FIFTH EXAMPLE - automatic code generation for
-- datetime conversion from style 0 to 14


-- Dynamic SQL using temporary table

USE AdventureWorks2008;

DECLARE @I INT = -1

DECLARE @SQLDynamic nvarchar(1024)

CREATE TABLE #SQL(STYLE int, SQL varchar(256), Result varchar(32))

WHILE (@I < 14)

BEGIN

      SET @I += 1

      INSERT #SQL(STYLE, SQL)

      SELECT @I, 'SELECT '+

      'CONVERT(VARCHAR, GETDATE(), '+CONVERT(VARCHAR,@I)+')'

      SET @SQLDynamic = 'UPDATE #SQL SET Result=(SELECT

      CONVERT(VARCHAR, GETDATE(), '+CONVERT(VARCHAR,@I)+

      ')) WHERE STYLE='+ CONVERT(VARCHAR,@I)

      PRINT @SQLDynamic

/* Printed in Messages - partial listing

UPDATE #SQL SET Result=(SELECT

CONVERT(VARCHAR, GETDATE(), 0)) WHERE STYLE=5

*/

     EXEC sp_executeSQL @SQLDynamic

END

SELECT * FROM #SQL

DROP TABLE #SQL

------------

-- SIXTH EXAMPLE - Communicating between parent and
-- child process using a shared temporary table

-- Temporary table created in parent session is visible to child

-- Parent session

-- Dynamic SQL

DECLARE @SQL nvarchar(512)

SELECT City='Montreal', Country = convert(varchar(30),'Canada')

INTO #City

-- Child session T-SQL script

SET @SQL = 'SELECT * FROM #City;

  INSERT #City VALUES(''Dallas'',''United States'');'

 

/* char(39)(ascii single quote) can be used to eliminate nested quotes

 

INSERT #City VALUES('+char(39)+'Dallas'+char(39)+','+char(39)+

                     'United States'+char(39)+');'

*/

PRINT @SQL

/*

SELECT * FROM #City; INSERT #City VALUES('Dallas','United States');

*/

EXEC sp_executeSQL @SQL

/* Result of select in child session

City        Country

Montreal    Canada

*/

SELECT * FROM #City

GO

/* Results

 

City        Country

Dallas      United States

Montreal    Canada

*/

DROP TABLE #City

GO

------------

-- SEVENTH EXAMPLE - The importance of QUOTENAME usage

-- QUOTENAME ensures that dynamic SQL will execute correctly

USE Northwind;

GO

 

-- SQL create stored procedure

-- SQL dynamic SQL

-- SQL quotename usage

CREATE PROCEDURE SelectFromAnyTable

                @table SYSNAME

AS

  BEGIN

    DECLARE  @SQL NVARCHAR(512)

    

    SET @SQL = 'select * from ' + QUOTENAME(@table)

    

    PRINT @SQL

 /*

 select * from [Order Details]

 */   

    EXECUTE sp_executeSQL   @SQL

  END

 

GO

 

-- SQL execute script

-- SQL execute dynamic sql stored procedure

EXEC SelectFromAnyTable   'Order Details'

 

/* Partial results

 

OrderID     ProductID   UnitPrice   Quantity    Discount

10248       11          14.00       12          0

10248       42          9.80        10          0

10248       72          34.80       5           0

10249       14          18.60       9           0

*/

------------

-- EIGTH EXAMPLE - Dynamic pivot query for crosstabulation

-- SQL pivot crosstab report

-- SQL dynamic pivot

-- SQL dynamic sql

-- SQL dynamic crosstab report with pivot

USE AdventureWorks

GO

DECLARE  @DynamicSQL  AS NVARCHAR(MAX)

DECLARE  @ReportColumnNames  AS NVARCHAR(MAX)

-- SQL pivot list generation dynamically

-- Dynamic pivot list        

SELECT  @ReportColumnNames = Stuff( (

SELECT ', ' + QUOTENAME(YYYY) AS [text()]

FROM   (SELECT DISTINCT YYYY=CAST (Year(OrderDate) as VARCHAR)

FROM Sales.SalesOrderHeader ) x

ORDER BY YYYY

-- SQL xml path for comma-limited list generation

FOR XML PATH ('')), 1, 1, '')

 

SET @DynamicSQL = N'SELECT * FROM (SELECT [Store (Freight Summary)]=s.Name,

YEAR(OrderDate) AS OrderYear,  Freight = convert(money,convert(varchar, Freight))

FROM Sales.SalesOrderHeader soh  JOIN Sales.Store s

ON soh.CustomerID = s.CustomerID) as Header

PIVOT (SUM(Freight) FOR OrderYear IN(' + @ReportColumnNames + N'))

AS Pvt ORDER BY 1'

 

PRINT @DynamicSQL -- Testing & debugging

/*

SELECT * FROM (SELECT [Store (Freight Summary)]=s.Name,

YEAR(OrderDate) AS OrderYear,  Freight = convert(money,convert(varchar, Freight))

FROM Sales.SalesOrderHeader soh  JOIN Sales.Store s

ON soh.CustomerID = s.CustomerID) as Header

PIVOT (SUM(Freight) FOR OrderYear IN([2001],[2002],[2003],[2004]))

AS Pvt ORDER BY 1

*/

-- SQL dynamic query execution

EXEC sp_executesql   @DynamicSQL

GO

/* Partial results

 

Store (Freight Summary) 2001        2002        2003        2004

Sundry Sporting Goods   1074.02     4609.31     4272.94     1569.04

Sunny Place Bikes       193.95      802.70      1095.83     411.62

Super Sports Store      102.15      743.51      427.80      301.68

Superb Sales and Repair 1063.69     1547.73     37.28       13.23

*/

------------

The World Leader in SQL Server 2008 Training
The future is just a CLICK away. Your future!
 
SQLUSA.com Home Page

Copyright 2005-2010, SMI Corp. All Rights Reserved.

SQL Server 2008 is a program product of Microsoft Corporation.
SQL Server 2005 is a program product of Microsoft Corporation.
SQL Server 2000 is a program product of Microsoft Corporation.