Table with date columns - conversion error with variables - sql-server

I have a table called [Tails] that looks like this.
Duration January February ....
1 0.8782 0.735
2 37.22 0.678
3 0.544 0.47347
What I need to do is lookup values for a given month depending on circumstances. So far I have (for example):
DECLARE #monthX Date = '04-01-2016'
Select [Duration],
iif(.....,datename(month,#monthX),....)
From [Tails]
This should be the equivalent of
SELECT [Duration], [APRIL] FROM [TAILS]
But my code results in a conversion error message. I've tried a few different ways to convert the variable to work like this after searching online for a solution and am getting nowhere.
Please can anyone advise? I am using SQL Server 2014.
Thank you so much

You can create your query dynamically and then use EXECUTE to execute it :
DECLARE #monthX Datetime
DECLARE #monthS varchar(20)
SET #monthX = '04-01-2016'
SET #monthS = datename(month,#monthX)
DECLARE #SQL varchar(100)
SET #SQL = 'select [Duration], [' + #monthS + '] from [Tails];'
EXECUTE (#SQL)

You can not select columns like that, but you could construct a dynamic sql query and execute it with sp_executesql like so:
declare #monthX Date = '20160101';
declare #sql nvarchar(max);
set #sql = 'Select [Duration], '+quotename(datename(month,#monthx))+' From [Tails];';
select #sql as sql;
exec sp_executesql #sql;
The query executed for this example would be:
Select [Duration], [January] From [Tails];
rextester demo: http://rextester.com/KBAS15857

If you want the whole column summed... Use this (minus the temp data for testing)
DECLARE #date DATETIME
SET #date = '2/28/17'
DECLARE #monthname VARCHAR(20)
SET #monthname = DATENAME(month, #date)
DECLARE #strSQL varchar(100)
CREATE TABLE #tempTable(duration int, january NUMERIC(28,12), february NUMERIC(28,12))
INSERT INTO #temptable(duration, january, february)
VALUES(1 , 0.8782 ,0.735)
INSERT INTO #temptable(duration, january, february)
VALUES(2 , 37.22 ,0.678)
INSERT INTO #temptable(duration, january, february)
VALUES(3 , 0.544 ,0.47347)
SET #strSQL = 'select SUM(' + #monthname + ') from #tempTable;'
EXECUTE (#strSQL)
DROP TABLE #tempTable

Related

Passing a date from query to a column header

I am working on a COVID database and I want to use part of the date from the Last_Update column of an import file, and use that as an alias for a column in that same file.
Here is an example of the import file:
FIPS County Province_State Country_Region Last_Update Lat Long Confirmed Deaths Recovered Active
45001 Abbeville South Carolina US 2020-05-30 02:32:48.00 34.22333378-82.46170658 39 0 0 39
22001 Acadia Louisiana US 2020-05-30 02:32:48.00 30.2950649 -92.41419698 401 23 0 378
51001 Accomack Virginia US 2020-05-30 02:32:48.00 37.76707161-75.63234615 7 12 0 815
Here is the expected result:
Province_State Country_Region 05-30
--------------------------------------
Abruzzo Italy 3237
Acre Brazil 5841
Aguascalientes Mexico 797
Aichi Japan 506
The Last_Update date column imports as 2020-05-30 02:32:48.0000000 and I have used the following code to extract the shortened date format for the new column header to read 05-30
DECLARE #ColumnName VARCHAR (50)
DECLARE #Date VARCHAR (50)
DECLARE #Query AS NVARCHAR (MAX)
SET #ColumnName = (SELECT TOP 1[Last_Update] FROM [DailyImport5.30.20])
SET #Date = SUBSTRING (#ColumnName,6,6)
PRINT #Date
Next I have tried to pass the variable of #Date to the new column header with no luck so far:
DECLARE #ColumnA nvarchar(max),
#ColumnB nvarchar(max),
#ColumnC nvarchar(max),
#ColumnName VARCHAR (50),
#Date VARCHAR (50),
#table nvarchar(max),
#sql nvarchar(max)
SET #table = 'DailyImport5.30.20'
SET #ColumnName ='(SELECT TOP 1[Last_Update] FROM [COVIDResearch].[dbo].[DailyImport5.30.20])'
SET #Date = 'SUBSTRING (#ColumnName,6,6)'
SELECT
#ColumnA = N'Province_State',
#ColumnB = N'Salary',
#ColumnC = N'#Date',
#table = N'[COVIDResearch].[dbo].[DailyImport5.30.20]'
SELECT #sql = N'SELECT ' +(#ColumnA)+','+(#ColumnB)+','+(#ColumnC)+ ' FROM '+(#table) +';'
EXEC sp_executesql #sql
I get this error:
Must declare the scalar variable "#Date".
I have also tried PIVOT but not been able to find how to read the date, trim it down, and then perform a pivot for all the results in the table. Not just a specified set of results.
Any advice is greatly appreciated!
Alex gave me the final push to solve this issue. Here is my final code to extract the date from the import file, shorten it to just the month and day, then insert it as the column header for use in a new table.
DECLARE #ColumnA nvarchar(max),
#ColumnB nvarchar(max),
#ColumnC nvarchar(max),
#ColumnName VARCHAR (50),
#Date VARCHAR (50),
#table nvarchar(max),
#sql nvarchar(max)
SET #table = 'DailyImport5.30.20'
SET #ColumnName =(SELECT TOP 1[Last_Update] FROM [COVIDResearch].[dbo].[DailyImport5.30.20])
SET #Date = SUBSTRING (#ColumnName,6,6)
SELECT #ColumnA = N'Province_State',
#ColumnB = N'Country_Region',
#ColumnC = 'Confirmed AS [' + #Date + ']',
#table = N'[COVIDResearch].[dbo].[DailyImport5.30.20]'
SELECT #sql = N'SELECT ' +(#ColumnA)+','+(#ColumnB)+','+(#ColumnC)+ ' FROM '+(#table) +';'
EXEC sp_executesql #sql
Thanks for your help!
If you "print" your query (via PRINT #sql) and copy the text to a new query window you will find that it has a syntax error near #Date column name. Variable names are not allowed as column names.
You need to give an alias to an existing data column. What you want to do is something along these lines:
.... Omitted for brevity
SELECT
#ColumnA = N'Province_State',
#ColumnB = N'Salary',
-- You need to give an alias to an existing column in [DailyImport5.30.20] table
-- Note: square brackets to avoid invalid identifiers, i.e. you assign value of #Date to #ColumnC.
#ColumnC = 'Confirmed AS [' + #Date + ']',
#table = N'[COVIDResearch].[dbo].[DailyImport5.30.20]'
SELECT #sql = N'SELECT ' +(#ColumnA)+','+(#ColumnB)+','+(#ColumnC)+ ' FROM '+(#table) +';'
EXEC sp_executesql #sql

Concatenate DateTime (yyyy-MM-dd HH:mm:ss.fff) to a string in a dynamic sql query

I have below DateTime value obtained using T-SQL GetDate() function and I am trying to concatenate it to a dynamic SQL query.
2020-02-25 11:35:29.240
and I am trying to concatenate to a WHERE clause like this:
CREATE PROCEDURE dbo.MyProc
#paramList varchar(200)
AS
BEGIN
DECLARE #sqlCommand nvarchar(max)
DECLARE #Now DATETIME = Getdate()
-- Do some stuff
SET #sqlCommand ='SELECT * FROM MyTable WHERE DeptId IN (' + #paramList + ') AND ''' + #Now + ''' <= datetimeField'
EXECUTE sp_executesql #sqlCommand
END
but it does not work.
Note: #paramList is a sp parameter that comes from C# .NET.
You can use use sp_executesql with parameter:
SET #sqlCommand ='SELECT * FROM MyTable WHERE #now <= datetimeField'
EXECUTE sp_executesql #sqlCommand, N'#now datetime', #Now = #Now
However, simple query will do what you want :
DECLARE #Now DATETIME = GETDATE()
SELECT *
FROM MyTable
WHERE datetimeField <= #Now;

Dynamic SQL "Declare Scalar Variable" error

I've created the following procedure and every time I try to execute it I get the error
Must declare the scalar variable #BatchId
Essentially, all that I'm trying to do is insert the contents of a raw table into a master table with a batch id (created by a sequencer) for all inserted rows. This seemed simple enough but isn't working properly.
CREATE PROCEDURE [dbo].[usp_SessionsAppend]
#RawTable NVARCHAR(500)
AS
DECLARE #BatchId BIGINT, #SQLString NVARCHAR(MAX)
SET #BatchId = NEXT VALUE FOR [dbo].[BatchID]
SET #SQLString =
'INSERT INTO [Master].[Sessions] (
[ImportTimestamp]
,[TransactionId]
,[ParticpantId]
,[ProviderId]
,[ActivityDate]
,[Attended]
,[Minutes]
,[SurveyCompleted]
,[Instructor]
,[InstructorID]
,[ProgramCode]
,[BatchId]
)
SELECT
GETDATE() AS [ImportTimeStamp]
,NEWID() AS [TransactionId]
,[ParticpantId]
,[ProviderId]
,[ActivityDate]
,[Attended]
,[Minutes]
,[SurveyCompleted]
,[Instructor]
,[InstructorID]
,[ProgramCode]
,#BatchId
FROM' + #RawTable
EXECUTE (#SQLString)
Any help or insight would be greatly appreciated.
Use sp_executesql to pass parameters into the dynamic SQL.
eg
declare #BatchId int = NEXT VALUE FOR [dbo].[BatchID]
declare #RawTable nvarchar(200) = 'foo';
declare #SQLString nvarchar(max) =
'INSERT INTO [Master].[Sessions] (
[ImportTimestamp]
,[TransactionId]
,[ParticpantId]
,[ProviderId]
,[ActivityDate]
,[Attended]
,[Minutes]
,[SurveyCompleted]
,[Instructor]
,[InstructorID]
,[ProgramCode]
,[BatchId]
)
SELECT
GETDATE() AS [ImportTimeStamp]
,NEWID() AS [TransactionId]
,[ParticpantId]
,[ProviderId]
,[ActivityDate]
,[Attended]
,[Minutes]
,[SurveyCompleted]
,[Instructor]
,[InstructorID]
,[ProgramCode]
,#BatchId
FROM ' + quotename(#RawTable)
print #SQLString
exec sp_executesql #SQLString, N'#BatchId int', #BatchId = #BatchId;

Call SQL stored proc with OUTPUT param from another stored proc

It seems very simple solution, but I can't figure it out. Please help.
I have to call a stored proc with OUTPUT param from another stored proc. I think one of the issues is dynamic SQL, but I don't know how else to write it since #SQLWhere will change dynamically within C# code.
This is the proc being called from another proc:
ALTER PROCEDURE [dbo].[USP_RetrieveTotalRecord]
#SQLWhere AS NVARCHAR(1000),
#TotalRecordsFound as varchar(16) OUTPUT
AS
BEGIN
SET NOCOUNT ON;
DECLARE #SQL AS NVARCHAR(Max)
SET #SQL='Select #TotalRecordsFound = Count(Table_ID)
From TableName Where ' + #SQLWhere
EXEC(#SQL)
return
END
Here is how I am calling it from another proc:
Declare #TotalRec AS NVARCHAR(16);
Declare #SQLWhere AS NVARCHAR(1000);
SET #SQLWhere='Date Between ''12/13/2016'' AND ''12/14/2016'''
EXECUTE USP_RetrieveTotalRecord #SQLWhere, #TotalRec output;
Here is the error I am trying to resolve:
Msg 137, Level 15, State 1, Line 30
Must declare the scalar variable "#TotalRecordsFound".
Don't do what you are trying to do, Only pass values to stored procedure and then build the dynamic sql inside your procedure, something like ......
ALTER PROCEDURE [dbo].[USP_RetrieveTotalRecord]
#StartDate DATE = NULL
,#EndDate DATE = NULL
,#TotalRecordsFound INT OUTPUT
AS
BEGIN
SET NOCOUNT ON;
DECLARE #SQL NVARCHAR(Max);
SET #SQL = N' Select #TotalRecordsFound = Count(Table_ID) '
+ N' From TableName Where 1 =1 '
+ CASE WHEN #StartDate IS NOT NULL THEN
N' AND [Date] >= #StartDate ' ELSE N' ' END
+ CASE WHEN #EndDate IS NOT NULL THEN
N' AND [Date] <= #EndDate ' ELSE N' ' END
EXEC sp_executesql #SQL
,N'#StartDate DATE, #EndDate DATE, #TotalRecordsFound INT OUTPUT'
,#StartDate
,#EndDate
,#TotalRecordsFound OUTPUT
END
Now #EndDate and #StartDate variables are optional , depending on what variable values you pass procedure will build the dynamic sql accordingly and return the results.
Also using parameterised query with sp_executesql will protect you against a possible SQL-Injection attach and also your proc will benefit from parameterised execution plans.
Not sure why you have a 2nd SP, just use one like so:
Declare #TotalRec AS NVARCHAR(16);
Declare #SQLWhere AS NVARCHAR(1000);
SET #SQLWhere='Date Between ''12/13/2016'' AND ''12/14/2016'''
SET #SQL='Select #TotalRecordsFound = Count(Table_ID)
From TableName Where ' + #SQLWhere
EXEC(#SQL)
Or use date variables if that's all you are using for selection (no dynamic sql necessary) - unless this is just a simplified example
--- comment section is broken, so, in response to get a value out, use something like this:
Ok - the simplest way is to use sp_ExecuteSQL
Declare #result int
Declare #sql nvarchar(max)
SET #SQL = ' SELECT COUNT(*) FROM MyTable'
exec sp_ExecuteSQL #sql, N' #Result int Output', #Result output
select #result as MyCount
M. ali, thanks for your help, but we have all SELECT, WHERE, and GROUP by criteria being passed from the application after dynamic selections. I needed a quick fix.
Finally I was able to resolve the issue using a temp table. I know they are not recommended, but I tried using Common table expression, table variable, but the #TotalRecordsFound was not visible outside the dynamic SQL. Therefore, created temp table, Inserted data into it using dynamic SQL, and then joined it with the next select statement.

SQL Server EXEC backup table with date dynamically

I am looking to backup a table and auto add the date to the end of the table name.
Here is what I have
declare #table char(36)= 'template_fields'
EXEC('select * into '+#table+'_'+'convert(date, getdate()) from '+#table)
And I want the end result to look something like
template_fields_09-09-2015
What am I missing here?
Just print what you do:
DECLARE #table NVARCHAR(MAX) = 'tab';
DECLARE #sql NVARCHAR(MAX) = 'select * into '+#table+'_'
+'convert(date, getdate()) from '+#table;
SELECT #sql;
you will get: select * into tab_convert(date, getdate()) from tab
You need to pass date with table name like:
SqlFiddleDemo
DECLARE #table NVARCHAR(MAX) = 'tab';
DECLARE #new_table NVARCHAR(MAX) = #table + '_' +
CONVERT(NVARCHAR(100), GETDATE(),105);
DECLARE #sql NVARCHAR(MAX) = 'select * into ' + #new_table + ' from '+ #table;
SELECT #sql;
/* Result select * into tab_09-09-2015 from tab */
-- EXEC(#sql);
First of all, do not use EXEC to run dynamic queries, use sp_executesql instead.
Second: When you want to build a SQL query with variable object names, use QUOTENAME().
DECLARE #table sys.sysname = 'mytable'
DECLARE #backup sys.sysname = #table + '_' + CONVERT(date, GETDATE());
DECLARE #sql NVARCHAR(MAX) = 'SELECT * INTO '
+ QUOTENAME(#backup) + ' '
+ FROM + ' '
+ QUOTENAME(#table);
EXEC sp_executesql
#stmt = #sql
Please note that, the sys.sysname is a built in data type (essentially an alias for NVARCHAR(128) NOT NULL) and SQL Server uses it internally for object names.
Note: I have no SQL Server instance accessible right now, so the above query can contain typos.
I ended up resolving this myself. While some nice responses were added I wrote my initial query more simply to achieve this. Thank you all for the help.
--Declare and initiate the table
declare #table varchar(36)= 'template_fields'
--Declare and initiate the date (YYYYMMDD) without dashes
declare #date varchar(10) = convert(int, convert(varchar(10), getdate(), 112))
--Execute the query with the variables resulting in a new table titled 'template_fields_20150909'
EXEC('select * into '+#table+'_'+#date+' from '+#table)

Resources