You are on page 1of 15

Generate dynamic SQL statements in SQL Server

Takeaway: When you need to solve a tricky database problem, the ability to generate SQL statements is a powerful tool although you must be careful when using it. Tim Chapman explores how you can use this functionality to generate SQL statements on the fly. When you need to solve a tricky database problem, the ability to generate SQL statements is a powerful tool although you must be careful when using it. This article explores how you can use this functionality to generate SQL statements on the fly.

Dynamic SQL statements


A dynamic SQL statement is constructed at execution time, for which different conditions generate different SQL statements. It can be useful to construct these statements dynamically when you need to decide at run time what fields to bring back from SELECT statements; the different criteria for your queries; and perhaps different tables to query based on different conditions. These SQL strings are not parsed for errors because they are generated at execution time, and they may introduce security vulnerabilities into your database. Also, SQL strings can be a nightmare to debug, which is why I have never been a big fan of dynamically built SQL statements; however, sometimes they are perfect for certain scenarios.

A dynamic example
The question I answer most often is, How can I pass my WHERE statement into a stored procedure? I usually see scenarios similar to the following, which is not valid TSQL syntax:
DECLARE @WhereClause NVARCHAR(2000) SET @WhereClause = ' Prouct = ''Computer''' SELECT * FROM SalesHistory WHERE @WhereClause

In a perfect world, it would make much more sense to do the following:


DECLARE @Product VARCHAR(20) SET @Product = 'Computer' SELECT * FROM SalesHistory WHERE Product = @Product

It isnt always this easy. In some scenarios, additional criteria is needed, and as tables grow wider, more and more criteria is often needed. This can typically be solved by writing different stored procedures for the different criteria, but sometimes the criteria is so different for each execution that covering all of the possibilities in a stored procedure is burdensome. While these stored procedures can be made to take into account every WHERE statement possible depending

on different parameters, this often leads to a degradation in query performance because of so many conditions in the WHERE clause. Lets take a look at how to build a simple dynamic query. First, I need a table and some data to query. The script below creates my SalesHistory table and loads data into it:
CREATE TABLE [dbo].[SalesHistory] ( [SaleID] [int] IDENTITY(1,1), [Product] [varchar](10) NULL, [SaleDate] [datetime] NULL, [SalePrice] [money] NULL ) GO SET NOCOUNT ON DECLARE @i INT SET @i = 1 WHILE (@i <=5000) BEGIN INSERT INTO [SalesHistory](Product, SaleDate, SalePrice) VALUES ('Computer', DATEADD(ww, @i, '3/11/1919'), DATEPART(ms, GETDATE()) + (@i + 57)) INSERT INTO [SalesHistory](Product, SaleDate, SalePrice) VALUES('BigScreen', DATEADD(ww, @i, '3/11/1927'), DATEPART(ms, GETDATE()) + (@i + 13)) INSERT INTO [SalesHistory](Product, SaleDate, SalePrice) VALUES('PoolTable', DATEADD(ww, @i, '3/11/1908'), DATEPART(ms, GETDATE()) + (@i + 29)) SET @i = @i + 1 END

Now I will build my stored procedure that accepts a WHERE clause. For the purpose of this example, I will assume that the WHERE clause was built dynamically from the calling client application.
CREATE PROCEDURE usp_GetSalesHistory ( @WhereClause NVARCHAR(2000) = NULL ) AS BEGIN DECLARE @SelectStatement NVARCHAR(2000) DECLARE @FullStatement NVARCHAR(4000) SET @SelectStatement = 'SELECT TOP 5 * FROM SalesHistory '

SET @FullStatement = @SelectStatement + ISNULL(@WhereClause,'') PRINT @FullStatement EXECUTE sp_executesql @FullStatement /* --can also execute the same statement using EXECUTE() EXECUTE (@FullStatement) */ END

I set the @WhereClause parameter to allow NULL values because we may not always want to pass a value in for the @WhereClause. For every execution of this stored procedure, every field is returned for the TOP 5 rows from SalesHistory. If there is a value passed in for the @WhereClause parameter, the executing statement will append that string to the @SelectStatement string. Then I use the stored procedure sp_executesql to execute the dynamically built SQL string.

sp_executesql or EXECUTE()
There are two ways to execute dynamic SQL in SQL Server: use the sp_executesql system stored procedure or the EXECUTE() operator. Sometimes the two methods can produce the same result, but there are differences in how they behave. The system stored procedure sp_executesql allows for parameters to be passed into and out of the dynamic SQL statement, whereas EXECUTE() does not. Because the SQL statement is passed into the sp_executesql stored procedure as a parameter, it is less suseptible to SQL injection attacks than EXECUTE(). Since sp_executesql is a stored procedure, passing SQL strings to it results in a higher chance that the SQL string will remain cached, which should lead to better performance when the same SQL statement is executed again. In my opinion, sp_executesql results in code that is a lot cleaner and easier to read and maintain. These reasons are why sp_executesql is the preferred way to execute dynamic SQL statements. In my previous example, I looked at how you can build a simple SQL statement by passing a WHERE clause into a stored procedure. But what if I want to get a list of parameter values from my dynamically built SQL statement? I would have to use sp_executesql because it is the only one of my two options that allows for input and output parameters. I am going to slightly modify my original stored procedure so that it will assign the total number of records returned from the SQL statement to an output parameter.
DROP PROCEDURE usp_GetSalesHistory GO

CREATE PROCEDURE usp_GetSalesHistory ( @WhereClause NVARCHAR(2000) = NULL, @TotalRowsReturned INT OUTPUT ) AS BEGIN DECLARE @SelectStatement NVARCHAR(2000) DECLARE @FullStatement NVARCHAR(4000) DECLARE @ParameterList NVARCHAR(500) SET @ParameterList = '@TotalRowsReturned INT OUTPUT' SET @SelectStatement = 'SELECT @TotalRowsReturned = COUNT(*) FROM SalesHistory ' SET @FullStatement = @SelectStatement + ISNULL(@WhereClause,'') PRINT @FullStatement EXECUTE sp_executesql @FullStatement, @ParameterList, @TotalRowsReturned = @TotalRowsReturned OUTPUT END GO

In the above procedure, I need to declare a parameter list to pass into the sp_executesql stored procedure because a value is being assigned to the variable at run time. The only other change to the sp_executesql call is that I am assigning the output parameter from the call to the local @TotalRowsReturned parameter in my usp_GetSalesHistory stored procedure. I can even call my usp_GetSalesHistory stored procedure similar to the way I did before, but with the addition of an output parameter to indicate the rows that were returned.
DECLARE @WhereClause NVARCHAR(2000), @TotalRowsReturned INT SET @WhereClause = 'WHERE Product = ''Computer''' EXECUTE usp_GetSalesHistory @WhereClause = @WhereClause, @TotalRowsReturned = @TotalRowsReturned OUTPUT SELECT @TotalRowsReturned

Caution
Although I am not a huge fan of using dynamic SQL statements, I believe it is a great option to have in your tool belt. If you decide to incorporate dynamic SQL into your production level code, be careful. The code is not parsed until it is executed, and it can potentially introduce security vulnerabilities that you do not want. If you are careful with your dynamic SQL statement, it can help you create solutions to some pretty tricky problems.

Building Dynamic SQL In a Stored Procedure

Introduction
A dynamic SQL in a stored procedure is a single Transact-SQL statement or a set of statements stored in a variable and executed using a SQL command. There may be several methods of implementing this in SQL Server. This article will show you a good method of doing this. Before getting into a detailed explanation, let me tell "When to Use Dynamic SQL?" We can't definitely say that a Static SQL will meet all our programming needs. A Dynamic SQL is needed when we need to retrieve a set of records based on different search parameters. Say for example - An employee search screen or a general purpose report which needs to execute a different SELECT statement based on a different WHERE clause. NOTE: Most importantly, the Dynamic SQL Queries in a variable are not compiled, parsed, checked for errors until they are executed.

sp_executesql Vs EXECUTE Command


A dynamically build Transact-SQL statements can be executed using EXECUTE Command or sp_executesql statement. Here, in this article in my examples, I'll be using sp_executesql which is more efficient, faster in execution and also supports parameter substitution. If we are using EXECUTE command to execute the SQL String, then all the parameters should be converted to character and made as a part of the Query before execution. But the sp_executesql statement provides a better way of implementing this. It allows us to substitute the parameter values for any parameter specified in the SQL String. Before getting into the actual example, let me differentiate these two commands with a simple example. Say - selecting a record from the employee table using the ID in the WHERE clause. The basic syntax for using EXECUTE command:
Collapse
EXECUTE(@SQLStatement)

The basic syntax for using sp_executesql:


Collapse
sp_executesql [@SQLStatement],[@ParameterDefinitionList], [@ParameterValueList]

Example 1.0 Collapse


/* Using EXECUTE Command */

/* Build and Execute a Transact-SQL String with a single parameter value Using EXECUTE Command */ /* Variable Declaration */ DECLARE @EmpID AS SMALLINT DECLARE @SQLQuery AS NVARCHAR(500) /* set the parameter value */ SET @EmpID = 1001 /* Build Transact-SQL String with parameter value */ SET @SQLQuery = 'SELECT * FROM tblEmployees WHERE EmployeeID = ' + CAST(@EmpID AS NVARCHAR(10)) /* Execute Transact-SQL String */ EXECUTE(@SQLQuery)

In the above example 1.0, there are two variables declared. The first variable @EmpID is used as a parameter to the SQL Query and second Variable @SQLQuery is used to build the SQL String. You can clearly see that the variable @EmpID is cast to a NVarchar type and made as a part of the SQL String. If you print the @SQLQuery string (PRINT @SQLQuery), you will get the actual SQL query as shown below:
Collapse
SELECT * FROM tblEmployees WHERE EmployeeID = 1001

Finally, the above query is executed using the EXECUTE command.


Example 1.1 Collapse
/* Using sp_executesql */ /* Build and Execute a Transact-SQL String with a single parameter value Using sp_executesql Command */ /* Variable Declaration */ DECLARE @EmpID AS SMALLINT DECLARE @SQLQuery AS NVARCHAR(500) DECLARE @ParameterDefinition AS NVARCHAR(100) /* set the parameter value */ SET @EmpID = 1001 /* Build Transact-SQL String by including the parameter */ SET @SQLQuery = 'SELECT * FROM tblEmployees WHERE EmployeeID = @EmpID' /* Specify Parameter Format */ SET @ParameterDefinition = '@EmpID SMALLINT' /* Execute Transact-SQL String */ EXECUTE sp_executesql @SQLQuery, @ParameterDefinition, @EmpID

In the example 1.1, there are two variables declared. The variable @EmpID is used as a parameter to the SQL Query and second variable @SQLQuery is used to build the SQL String, the third variable @ParameterDefinition is used to specify the parameter format before executing the SQL string. If you print the @SQLQuery string (PRINT @SQLQuery), you will get the query as shown below:

Collapse
SELECT * FROM tblEmployees WHERE EmployeeID = @EmpID

Here, in this example, you can clearly see the parameter @EmpID is included in the statement. Finally, sp_executesql takes the necessary information to do the parameter substitution and execute the dynamically built SQL string.
1. @SQLQuery --> contains the SQL statement 2. @ParameterDefinition --> contains the Parameter Definition 3. @EmpID --> contains the parameter value to be substituted to the parameter in the SQL statement.

NOTE: The parameters included in the Dynamic SQL string must have a corresponding entry in the Parameter Definition List and Parameter Value List.

Dynamic SQL in a Stored Procedure


This part of the article explains with a real-world example and sample procedure "How to Build and Execute a Dynamic SQL in a stored procedure?"
Example 2.0

Let us take a simple example - Employee Table with common fields such as EmployeeID, Name, Department, Designation, JoiningDate, Salary and Description. You can use the following Transact-SQL CREATE TABLE statement to create a Employee Table within your database.
Collapse
/* Transact-Sql to create the table tblEmployees */ CREATE TABLE tblEmployees ( EmployeeID SMALLINT IDENTITY(1001,1) NOT NULL, EmployeeName NVARCHAR(100) NOT NULL, Department NVARCHAR(50) NOT NULL, Designation NVARCHAR(50) NOT NULL, JoiningDate DATETIME NOT NULL, Salary DECIMAL(10,2) NOT NULL, [Description] NVARCHAR(1000) NULL )

The following INSERT statements insert some sample records into the tblEmployee table:
Collapse
/* Transact SQL to insert some sample records into tblEmployee table */ INSERT INTO tblEmployees (EmployeeName, Department, Designation,

JoiningDate, Salary, [Description]) VALUES ('John Smith', 'IT Research', 'Research Analyst', '02/08/2005', 23000.00, 'Analyst since 2005') INSERT INTO tblEmployees (EmployeeName, Department, Designation, JoiningDate, Salary, [Description]) VALUES ('John Micheal', 'IT Operations', 'Manager', '07/15/2007', 15000.00, NULL) INSERT INTO tblEmployees (EmployeeName, Department, Designation, JoiningDate, Salary, [Description]) VALUES ('Will Smith', 'IT Support', 'Manager', '05/20/2006', 13000.00, 'Joined last year as IT Support Manager')

We programmers may get an assignment to develop an Employee search screen or generate an Employee listing report which will search the database and return a result based on the search criteria. In this case, the search Interface should be flexible enough to search the database for all possible criteria. A user may require to search for the following details:
y y y y y y

Search for specific Employee Detail with the Name List of Employees in a specific Department List of Employees in a specific Designation List of Employees joined the organization last year List of Employees whose Salary >= some specific Amount Any of these conditions listed above or all of these

I have listed few possible conditions here. There could be many other possibilities also which completely depend on the user requirement. Here let us take these listed few possible criteria and write a single stored procedure that builds a Dynamic SQL which will serve our purpose in searching for the Details in the Employee Table. The following CREATE PROCEDURE Statement will create a stored procedure "sp_EmployeeSelect" with the necessary input parameters and variables to build the Dynamic SQL.
Collapse
/* This stored procedure builds dynamic SQL and executes using sp_executesql */ Create Procedure sp_EmployeeSelect /* Input Parameters */ @EmployeeName NVarchar(100), @Department NVarchar(50), @Designation NVarchar(50), @StartDate DateTime, @EndDate DateTime, @Salary Decimal(10,2) AS

Set NoCount ON /* Variable Declaration */ Declare @SQLQuery AS NVarchar(4000) Declare @ParamDefinition AS NVarchar(2000) /* Build the Transact-SQL String with the input parameters */ Set @SQLQuery = 'Select * From tblEmployees where (1=1) ' /* check for the condition and build the WHERE clause accordingly */ If @EmployeeName Is Not Null Set @SQLQuery = @SQLQuery + ' And (EmployeeName = @EmployeeName)' If @Department Is Not Null Set @SQLQuery = @SQLQuery + ' And (Department = @Department)' If @Designation Is Not Null Set @SQLQuery = @SQLQuery + ' And (Designation = @Designation)' If @Salary Is Not Null Set @SQLQuery = @SQLQuery + ' And (Salary >= @Salary)' If (@StartDate Is Not Null) AND (@EndDate Is Not Null) Set @SQLQuery = @SQLQuery + ' And (JoiningDate BETWEEN @StartDate AND @EndDate)' /* Specify Parameter Format for all input parameters included in the stmt */ Set @ParamDefinition = ' @EmployeeName NVarchar(100), @Department NVarchar(50), @Designation NVarchar(50), @StartDate DateTime, @EndDate DateTime, @Salary Decimal(10,2)' /* Execute the Transact-SQL String with all parameter value's Using sp_executesql Command */ Execute sp_Executesql @SQLQuery, @ParamDefinition, @EmployeeName, @Department, @Designation, @StartDate, @EndDate, @Salary If @@ERROR <> 0 GoTo ErrorHandler Set NoCount OFF Return(0) ErrorHandler: Return(@@ERROR) GO

This sample stored procedure takes few parameter's as input and uses two variables to build and execute. @SQLQuery which is used to build the dynamic SQL-statement. @ParamDefinition which is used to define the Parameter's format. Whiling building the SQL string in each step, an IF-statement is used to check whether that inputted parameter is Null or not. If it is not NULL, then that parameter will be included in the SQL statement which basically adds a condition in the WHERE clause of the SQL statement. You can clearly see in the procedure that the variable

@ParamDefinition contains all the parameter lists and finally sp_Executesql takes SQLquery, parameter list and the parameter values to executes a SELECT statement.

Let us consider some of the criteria listed above and see how this stored procedure works.
1. Search for specific Employee Detail with the name. Collapse
/* 1. Search for specific Employee Detail with the Name say 'John Smith'. */ EXEC sp_EmployeeSelect 'John Smith', NULL, NULL, NULL, NULL, NULL

Executing the above statement will list the details of the Employee "John Smith".
2. List of Employees in a specific Department, AND 3. List of Employees in a specific Designation. Collapse
/* 2. List of Employees in a specific Department. AND 3. List of Employees in a specific Designation. */ /* Say Department = 'IT Operations' AND Designation = 'Manager'*/ EXEC sp_EmployeeSelect NULL, 'IT Operations', 'Manager', NULL, NULL, NULL

Executing the above statement will list the Details of Managers in the IT Operations Department.

Using Like Operator, IN Operator and Order By In Dynamic SQL


when we are building Dynamic SQL, there may be some instances where we need to use LIKE operator, IN operator and Order BY Clause. But the parameters used with these operators and Order By Clause doesn't work the way as they normally do for "=" and "Between" operator while using sp_executesql. Generally sp_executesql doesn't do a parameter substitution for order by clause and doing so causes a column-referencing problem. Straightly Using LIKE operator and IN operator causes syntax error, which cannot be rectified when we are including the parameter into the Dynamic SQL statement. This problem can be resolved by including the actual parameter value in the Dynamic SQL statement. Below are the examples that show how to use Like Operator, IN Operator and OrderBy clause while using sp_executesql.
Example 3.0 - Using LIKE Operator

Example 3.0 uses LIKE operator to select the list of Employees with the Name 'John'. Here in this example, the parameter is not included in the SQL statement, instead the actual value of the

parameter is added to the SQL statement. So here, there is no need of parameter definition for executing the SQL string. The same applies to the other two examples shown below:
Collapse
/* Variable Declaration */ DECLARE @EmpName AS NVARCHAR(50) DECLARE @SQLQuery AS NVARCHAR(500) /* Build and Execute a Transact-SQL String with a single parameter value Using sp_executesql Command */ SET @EmpName = 'John' SET @SQLQuery = 'SELECT * FROM tblEmployees WHERE EmployeeName LIKE '''+ '%' + @EmpName + '%' + '''' EXECUTE sp_executesql @SQLQuery

Example 3.1 - Using IN Operator

Example 3.1 uses IN operator to select the Employee details ( ID = 1001, 1003 ):
Collapse
/* Variable Declaration */ DECLARE @EmpID AS NVARCHAR(50) DECLARE @SQLQuery AS NVARCHAR(500) /* Build and Execute a Transact-SQL String with a single parameter value Using sp_executesql Command */ SET @EmpID = '1001,1003' SET @SQLQuery = 'SELECT * FROM tblEmployees WHERE EmployeeID IN(' + @EmpID + ')' EXECUTE sp_executesql @SQLQuery

Example 3.2 - Using Order By Clause

Example 3.2 sorts the Employee records by "Department" column.


Collapse
/* Variable Declaration */ DECLARE @OrderBy AS NVARCHAR(50) DECLARE @SQLQuery AS NVARCHAR(500) /* Build and Execute a Transact-SQL String with a single parameter value Using sp_executesql Command */ SET @OrderBy = 'Department' SET @SQLQuery = 'SELECT * FROM tblEmployees Order By ' + @OrderBy EXECUTE sp_executesql @SQLQuery

Conclusion

In this article, I have explained with few examples "How to Build and Execute Dynamic SQL in stored procedures". Hope this article will help to understand and write Dynamic SQL in a good way.

Another Dynamic SQL CrossTab Stored Procedure


First off, before going any further make sure you have read the hall of fame SQLTeam article by Rob Volk on generating crosstab results using a flexible, dynamic stored procedure that has been viewed over 100,000 times! This entire concept and pretty much all of the ideas I've had regarding this topic and this techinique in general are all due to Rob's great work and his very clever stored procedure. It must be crosstab season or something, because lately I've been getting quite a few emails and comments about an alternative stored procedure that I've posted in the comments to that article that has been helping quite a few users. To potentially help others out there with this common request (which I still feel should be mostly done at the presentation layer, but I suppose it's not always possible) here's a quick recap/reprint of my adaptation of Rob's excellent idea and some notes. The main difference between Rob's original stored procedure and mine are that
y y y y

you can summarize multiple values it only creates columns based on your actual select statement ( not based on all rows in a table) it works fine for multi-users (no global temp tables) it allows you to easily specify default values for your pivots

Note that if you read the comments from the article, you'll see lots of modifications and adaptations of Rob's original that do address some of these issues, but I am proud of the brevity and flexibility of my code and I feel that it works well and is easily modified (see the end of this article for one idea). Depending on your needs, it may be useful to incorporate some of the other ideas presented in the article and the comments, so be sure to do some research if necessary or if you are interested in learning more. First, here's the code for the procedure:

create procedure CrossTab (@Select varchar(1000), @PivotCol varchar(100),

@Summaries varchar(100), @GroupBy varchar(100), @OtherCols varchar(100) = Null) AS set nocount on set ansi_warnings off declare @Vals varchar(8000); set @Vals = ''; set @OtherCols= isNull(', ' + @OtherCols,'') create table #temp (Pivot varchar(100))

insert into #temp exec ('select distinct convert(varchar(100),' + @PivotCol + ') as Pivot FROM (' + @Select + ') A') select @Vals = @Vals + ', ' + replace(replace(@Summaries,'(','(CASE WHEN ' + @PivotCol + '=''' + Pivot + ''' THEN '),')[', ' END) as [' + Pivot ) from #Temp order by Pivot drop table #Temp exec ( 'select ' + @GroupBy + @OtherCols + @Vals + ' from (' + @Select + ') A GROUP BY ' + @GroupBy) set nocount off set ansi_warnings on

And here's a description of the parameters and how to use it:


y

y y y

Select - This is the SQL statement or table you are querying. It can be any valid SELECT statement, with JOINS, WHERE clauses, TOP, etc -- anything that you can cut and paste into query analyzer and execute. (And, in fact, you should always do this when testing things out). PivotCol - This is the column (or a valid expression) that you wish to pivot on. Summaries - The summaries you wish to perform. Note that this is plural; you can summarize multiple columns if you wish. See below for more information. GroupBy - This is the list of the non-pivot columns you wish to group by and return, separated by commas.

OtherCols (optional) - Any other columns to return that you are not grouping by, also separated by commas. Make sure that this list does not contain references to columns that are not being summarized or grouped.

Here's the format you should use when specifying the Summaries parameter: SUM(Field ELSE DefaultValue)[Prefix], .... First, list the aggregate function you wish to use, and within that function put the column you wish to summarize, and add an ELSE clause with what that column's default value is. For example, put 0 if you wish to display all 0's for empty columns, or NULL if you wish to display nulls. Next, immediately following the aggregate function (with no spaces) put the prefix for the column name in brackets. This is what will be appended to the beginning of the column name, followed by the value from the pivot column. Leave as [] to just use the pivot column's value as the field name. Finally, you may have multiple summaries just seperate them by comma's. Remember if you have many pivot values, you will probably end up with too many columns and/or a T-SQL statement > 8000 characters so you may get an error. Examples: If the pivot column is "Employee", with values of 001, 002, 003 and 004:
SUM(Hours ELSE 0)[]

returns column headings of 001, 002, 003, 004, and returns a 0 in all "empty" fields.
SUM(Hours ELSE 0)[Hours], MAX(Date ELSE Null)[MaxDate]

returns column headings of Hours001, MaxDate001, Hours002, MaxDate002, Hours003, MaxDate003, ..etc ...
SUM(Amount ELSE Null)[]

returns column headings of 001,002,003,004 and returns a NULL in all "empty" fields. Note that you can use SUM(Amount)[] as a shortcut, since ELSE NULL is redundant and is the default behavior.
SUM(Amount ELSE 0)[Amount], COUNT(Amount)[Qty]

returns column headings of Amount001, Qty001, Amount002, Qty002, ... etc ...

Here are some samples using either Northwind or Pubs:


exec CrossTab 'SELECT LastName, OrderDate FROM northwind..Employees Employees INNER JOIN northwind..Orders Orders ON (Employees.EmployeeID=Orders.EmployeeID) ', 'Year(OrderDate)', 'Count(LastName)[]', 'LastName' exec CrossTab 'select titles.*, stores.stor_name, sales.qty, sales.stor_id from pubs..titles titles inner join pubs..sales sales on (sales.title_id=titles.title_id) inner join pubs..stores stores on sales.stor_id = stores.stor_id ', 'stor_id', 'SUM(qty ELSE 0)[Qty], MAX(stor_name ELSE '''')[MaxStoreName], COUNT(1 ELSE 0)[Count]', 'title', 'Count(*) as TotalCount'

You might also like