I need help with a piece of code in a stored procedure that returns a dataset to a .NET app containing a variable set of columns--standard columns, plus user-defined columns. My code creates a temp table to hold the dataset and appends the custom columns. The issue I'm having is with the population of these custom columns. (By the way, my code needs to be compatible with Microsoft SQL Server 2008 R2).
I want to use dynamic SQL to put together an Update statement that updates the values of the custom columns in a temp table using SQL snippets stored in a lookup table.
For example, a user might want a custom field that contains an employee's name concatenated a certain way (e.g. "Last Name, First Name"), so the SQL snippet for the custom field would be "LastName + ', ' + FirstName" to concatenate the FistName and LastName fields in the temp table. That's easy. The hard part is when the custom field needs to get populated using a variable passed into the sproc, say to create a unique ID (e.g. The SQL snippet for the custom field is 'Inc_' + CAST(MONTH(@PayrollDate) AS VARCHAR)' to get something like 'Inc_10' if the input parameter @PayrollDate is '10/15/17').
Are still with me? Good, let's do some SQL.
Let's assume we have a temp table with our standard fields and then append a couple of custom fields, as follows (please don't pay attention to my alter table method; in my real sproc, I use dynamic SQL to append the fields, based on saved values in a lookup table).
-- 1. Create the temp table with the standard fields
IF OBJECT_ID('tempdb..#MyTempTable') IS NOT NULL
DROP TABLE #MyTempTable
CREATE TABLE #MyTempTable (
EmpID VARCHAR(50),
FirstName VARCHAR(100),
LastName VARCHAR(100),
EarningsValue MONEY)
-- 2. Add sample earnings data to the temp table
INSERT INTO #MyTempTable (EmpID,FirstName,LastName,EarningsValue) VALUES('1234','Tom','Jones',525.50)
INSERT INTO #MyTempTable (EmpID,FirstName,LastName,EarningsValue) VALUES('4455','Mary','Smith',800.25)
INSERT INTO #MyTempTable (EmpID,FirstName,LastName,EarningsValue) VALUES('9876','Aaron','Lee',200.00)
-- 3. Add the custom fields to the temp table
ALTER TABLE #MyTempTable ADD EmployeeName VARCHAR(100)
ALTER TABLE #MyTempTable ADD BatchID VARCHAR(50)
I know of two methods to execute dynamic SQL to populate my custom fields. The method that works partway is the EXEC(@SQL) method, where you do something like this:
DECLARE @SQL VARCHAR(1000), @CustomField VARCHAR(50), @SQLSnippet VARCHAR(500)
SELECT @CustomField = 'EmployeeName', @SQLSnippet = 'LastName + '','' + FirstName'
SET @SQL = 'UPDATE #MyTempTable SET ' + @CustomField + ' = ' + @SQLSnippet
EXEC(@SQL)
If you were to do PRINT @SQL instead of EXEC(@SQL), you would get:
UPDATE #MyTempTable SET EmployeeName = LastName + ',' + FirstName
If I do SELECT * FROM #MyTempTable, I'll see my 'EmployeeName' custom field populated just fine.
The other dynamic SQL method to use is sp_executesql. However, if I try to do my UPDATE, I get NOTHING, because the it doesn't recognize @CustomField in my SET statement.
DECLARE @NSQL NVARCHAR(1000), @CustomField NVARCHAR(50), @SQLSnippet NVARCHAR(500)
SELECT @CustomField = 'EmployeeName', @SQLSnippet = 'LastName + '','' + FirstName'
SET @NSQL = 'UPDATE #MyTempTable SET @CustomField = @SQLSnippet'
EXECUTE sp_executesql @NSQL,N'@CustomField NVARCHAR(50), @SQLSnippet NVARCHAR(500)',@CustomField,@SQLSnippet
If I do PRINT @NSQL, I get UPDATE #MyTempTable SET @CustomField = @SQLSnippet. Obviously, that doesn't look good, but theoretically the values passed into the @CustomField and @SQLSnippet fields should work, shouldn't it?
At this point, you're thinking, "Steve, why don't you use the EXEC(@SQL) method and forget the sp_executesql nonsense?" Ah, but there's a catch.
In the case where I need to use dynamic SQL using a variable in the SQL snippet, the EXEC(@SQL) method fails. It complains with 'Must declare the scalar variable "@PayrollDate"'. Really? Yeah, really. Here, try it...
DECLARE @SQL VARCHAR(1000), @CustomField VARCHAR(50), @SQLSnippet VARCHAR(500), @PayrollDate SMALLDATETIME
SET @PayrollDate = '10/15/17'
SELECT @CustomField = 'BatchID', @SQLSnippet = '''INC_'' + CAST(MONTH(@PayrollDate) AS VARCHAR)'
SET @SQL = 'UPDATE #MyTempTable SET ' + @CustomField + ' = ' + @SQLSnippet
EXEC(@SQL)
From what I've researched online, only sp_executesql works with parameters in the dynamic SQL. However, I still don't get any results using it. Here's the dynamic SQL using sp_executesql:
DECLARE @NSQL NVARCHAR(1000), @CustomField NVARCHAR(50), @SQLSnippet NVARCHAR(500), @PayrollDate SMALLDATETIME
SET @PayrollDate = '10/15/17'
SELECT @CustomField = 'BatchID', @SQLSnippet = '''INC_'' + CAST(MONTH(@PayrollDate) AS VARCHAR)'
SET @NSQL = 'UPDATE #MyTempTable SET @CustomField = @SQLSnippet'
EXECUTE sp_executesql @NSQL, N'@CustomField NVARCHAR(50),@SQLSnippet NVARCHAR(500),@PayrollDate SMALLDATETIME',@CustomField,@SQLSnippet,@PayrollDate
If you do a SELECT * FROM #MyTempTable, the BatchID custom field is NULL. Grrrr!
So how do I get the blanking dynamic SQL to work properly? Do I use the EXEC(@SQL) method or the sp_executesql method, and how? Much appreciated!