Appending variables inside dynamic sql in sql server - sql

I'm having trouble building a dynamic sql string to run an openquery. When I print the query string it evaluates the variable name as string instead of the actual value. Here's what I have:
Declare #tsql varchar(1000)
Declare #book_review_start as date
Declare #book_review_end as date
set #book_review_start = convert(varchar(10),DATEADD(month, DATEDIFF(month, 0, GETDATE())-2, 0), 120)
set #book_review_end = convert(varchar(10), DATEADD(mm, DATEDIFF(mm, 0, GETDATE()), -2), 120)
Set #tsql = 'select * from openquery(authorsdb, ''select distinct ssn as bsn
from authors.dbo.nytimes where review_date between '' + #book_review_start + 'and' + '#book_review_end' + 'and review = 'annual'
and city_name = ''
and review_hrs = 0
and review_days = 0')'
That throws all kinds of conversion errors and such.

1) You need 1 or more extra ' single quote characters in 1 or more places in your statement.
2) The DATE values need to converted to string / VARCHAR since you are concatenating string to generate the dynamic SQL statement.
The following works.
DECLARE #tsql VARCHAR(1000)
DECLARE #book_review_start AS DATE
DECLARE #book_review_end AS DATE
SET #book_review_start = DATEADD(month, DATEDIFF(month, 0, GETDATE())-2, 0)
set #book_review_end = DATEADD(mm, DATEDIFF(mm, 0, GETDATE()), -2)
Set #tsql = 'SELECT * FROM OPENQUERY(authorsdb, ''SELECT DISTINCT ssn AS bsn FROM authors.dbo.nytimes WHERE review_date BETWEEN'''
+ CONVERT(varchar(20),#book_review_start) + ''' AND ''' + CONVERT(varchar(20),#book_review_end ) + ''''
+ ' AND review = ''annual'' AND city_name = '''' AND review_hrs = 0 AND review_days = 0 )'
PRINT #tsql
The OUTPUT of the PRINT Statement is as follows.
SELECT * FROM OPENQUERY(authorsdb, 'SELECT DISTINCT ssn AS bsn FROM
authors.dbo.nytimes WHERE review_date BETWEEN'2016-05-01' AND
'2016-06-30' AND review = 'annual' AND city_name = '' AND review_hrs =
0 AND review_days = 0 )

If the intent is to eventually do this:
exec sp_executesql #tsql
then, as a minimum you must:
1 Make #tsql an nvarchar variable as opposed to varchar.
2 As suggested by Serg, all single quotes in the sql part become 4 single quotes. For example, this:
and city_name = ''
becomes this:
and city_name = ''''''''
3 You need spaces around words. For example this:
where review_date between '' + #book_review_start + 'and'
must be this:
where review_date between ' + #book_review_start + ' and '
This should get you started. Read the other answers as well.

Your query issues are
- #book_review_start / end declared DATE, should be VARCHAR to take part in concatenation
- to have a quote in a quoted string you need double quote, to have quoted string in a quoted string you need 4 quotes
Try
Declare #tsql varchar(1000)
Declare #book_review_start varchar(10)
Declare #book_review_end varchar(10)
set #book_review_start = convert(varchar(10),DATEADD(month, DATEDIFF(month, 0, GETDATE())-2, 0), 120)
set #book_review_end = convert(varchar(10), DATEADD(mm, DATEDIFF(mm, 0, GETDATE()), -2), 120)
Set #tsql = 'select * from openquery(authorsdb, ''select distinct ssn as bsn
from authors.dbo.nytimes where review_date between ''''' + #book_review_start + ''''' and ''''' + #book_review_end + ''''' and review = ''''annual''''
and city_name = ''''''''
and review_hrs = 0
and review_days = 0'')' ;
select #tsql;

Related

Stored procedure is not accepting null

I am executing this stored procedure and it works fine, but when I am calling from the frontend side, it returns no rows.
ALTER PROCEDURE [dbo].[USP_GetRequest_DataListForViewPrint]
#RequestNo VARCHAR(50) = null,
#FromDate varchar(50) = null,
#ToDate varchar(50) = null
AS
BEGIN
DECLARE #SQLStr varchar(8000), #WHERECRI VARCHAR(1000) = NULL
IF (#RequestNo IS NOT NULL)
BEGIN
SET #WHERECRI = 'WHERE RequestNo='+ CHAR(39)+#RequestNo+ CHAR(39) ;
END
ELSE
BEGIN
SET #WHERECRI = ' WHERE RequestDate BETWEEN ' + CHAR(39) + CONVERT(varchar(10), CONVERT(datetime, #FromDate, 105), 102) + CHAR(39) + 'AND' + CHAR(39) + CONVERT(varchar(10), CONVERT(datetime, #ToDate, 105), 102) + CHAR(39);
END
SET #SQLStr = 'SELECT Id, RequestStatus, RequestDate, RequestNo FROM CYGNUX_Request_Header ' + #WHERECRI;
PRINT #SQLStr;
EXEC(#SQLStr);
END
In the frontend it take parameter this way and this is does not return any data:
EXEC USP_GetRequest_DataListForViewPrint '', '08-06-2020 00:00:00','16-06-2020 00:00:00'
But if I execute this in SQL Server this way it is returning data. I don't know what's wrong in my frontend
EXEC USP_GetRequest_DataListForViewPrint null, '08-06-2020 00:00:00','16-06-2020 00:00:00'
Please help me - how can I solve this?
In the frontend you are not passing NULL but an empty string, therefor your SP is executing the Select with a WHERE on RequestNo equal to an empty string which probably doesn't return any record.

Dynamic query and use of variables

The query below works if the 2 dates are hard coded, however, I would like to replace them with the 2 variables #FirstDayM and #LastDayM.
When I do so, it returns the following error
"Conversion failed when converting date and/or time from character string"
DECLARE #sql varchar(max)
DECLARE #FirstDayM DATE = DATEADD(MONTH, DATEDIFF(MONTH, 0, GETDATE())-1, 0)
DECLARE #LastDayM DATE = DATEADD(MONTH, DATEDIFF(MONTH, -1, GETDATE())-1, -1);
SELECT #sql = Coalesce(#sql + ' UNION ALL ', '') + 'SELECT COUNT(C1CustID) AS CertsCount, ''' + QuoteName(name)+ ''' as DBname FROM ' + QuoteName(name) + '.dbo.T_C1CustCourse'+
' WHERE C1CertificationDate_N >= '+'''2018-01-01'''+' AND C1CertificationDate_N <= '+'''2018-01-31'''
FROM sys.databases WHERE database_id > 4 AND state = 0;
EXEC (#sql);
Use sp_executesql. Always. It makes it easy to put parameters into queries. Even if the dynamic query does not start with the parameter, you might decide to add one later.
declare #sql nvarchar(max);
declare #firstDayM date;
declare #lastDayM date;
set #firstDayM = ?;
set #lastDayM = ?;
SELECT #sql = Coalesce(#sql + ' UNION ALL ', '') + '
SELECT COUNT(C1CustID) AS CertsCount, ''' + QuoteName(name)+ ''' as
DBname
FROM ' + QuoteName(name) + '.dbo.T_C1CustCourse' + '
WHERE C1CertificationDate_N >= #FirstDayM AND C1CertificationDate_N
<= #LastDayM'
FROM sys.databases
WHERE database_id > 4 AND state = 0;
EXEC sp_executesql #sql, N'#FirstDayM date, #lastDayM date',
#FirstDayM=#FirstDayM, #lastDayM=#lastDayM;

Error message Conversion failed when converting datetime from character string

ALTER PROCEDURE [dbo].[TEST_01]
(
#StartDate DateTime,
#EndDate DateTime
)
AS
BEGIN
SET NOCOUNT ON;
Declare #sql as nvarchar(MAX);
SET #sql = #sql + ';WITH CTE_ItemDetails
MAX(D.Name) as Name,
SUM(ISNULL(DT.col1, 0)) AS col1,
SUM(ISNULL(DT.col2, 0)) AS col2,
SUM(ISNULL(DT.col3, 0)) AS col3,
GROUPING(D.ItemType) AS ItemTypeGrouping
FROM Items D
INNER JOIN Details DT ON DT.ItemId = D.ItemId
INNER JOIN Report R ON R.ReportId = DT.ReportId
where 1=1'
SET #sql = #sql + ' AND (R.ReportDate >= ' + #StartDate + 'AND R.ReportDate <=' + #EndDate +')'
IF #someOtherVariable is not null
SET #sql = #sql + ' AND R.someColumn IN (''' +replace(#someOtherVariableValues,',','')+''+')'
SET #sql = #sql + 'SELECT col1, col2, col3 FROM CTE_ItemDetails'
EXECUTE (#sql)
END
I have a stored procedure that is similar to the T-SQL code above.
(Note that i have removed lots of code that i feel isn't relevant to the error i'm getting)
I'm getting the below error when i execute it.
Conversion failed when converting datetime from character string.
My parameters have values in below format
exec TEST_01 #StartDate=N'4/1/2016 12:00:00 AM',#EndDate=N'4/30/2016 12:00:00 AM'
It looks like the trouble is in the way i'm dynamically setting the SQL statement at line below
SET #sql = #sql + ' AND (R.ReportDate >= ' + #StartDate + 'AND R.ReportDate <=' + #EndDate +')'
What is the best date formatting i can apply to avoid the error.
You should use parameters via sp_executesql.
But your immediate problem is this line:
SET #sql = #sql + ' AND (R.ReportDate >= ' + #StartDate + 'AND R.ReportDate <=' + #EndDate +')'
It should look more like:
SET #sql = #sql + ' AND (R.ReportDate >= ''' + convert(varchar(10), #StartDate, 121) + ''' AND R.ReportDate <= ''' + convert(varchar(10), #EndDate, 121) +''')' ;
Note the inclusion of explicit type casting to a string and the double single quotes so the date literal is not interpreted as 2016 - 04 - 14 (i.e. 2000).
The better method of using parameters looks like:
SET #sql = #sql + ' AND (R.ReportDate >= #StartDate AND R.ReportDate <= #EndDate)' ;
. . .
exec sp_executesql #sql, N'#StartDate date, #EndDate date)', #StartDate = #StartDate, #EndDate = #EndDate;
It is easier to read the SQL statement. The type issues are handled through parameters. And, the query plan is more readily stashed. Unfortunately, parameters only work for constants, not for column or table names, for instance.

Conversion date and/or time from character string

I have a big procedure which consists mostly dynamic SQL. I am having issues with setting one of the date fields.
DECLARE #WorkDate DATETIME
SET #WorkDate = 'SELECT MIN(__Insert_Date) FROM ' + #DatabaseName + '.'
+ #SchemaName + '.' + #TableName + '_Hist'
SET #WorkDate = DATEADD(DAY, DATEDIFF(DAY, '19000101', #WorkDate), '19000101')
This is part of a big procedure. So when I execute the above query I am getting this error:
Msg 241, Level 16, State 1, Line 68
Conversion failed when converting date and/or time from character string.
#WorkDate is DATETIME and your setting it at as a sting thats why the conversion is failing
EDIT :
Try this:
DECLARE #WorkDate DATETIME, #WorkDateString varchar(100)
SET #WorkDateString = 'SELECT MIN(__Insert_Date) FROM ' + #DatabaseName + '.'
+ #SchemaName + '.' + #TableName + '_Hist'
SET #WorkDate = DATEADD(DAY, DATEDIFF(DAY, '19000101', #WorkDate), '19000101')
If you need to insert the #WorkDate into the select string where __Insert_Date is then you need to reverse the order to look like this
DECLARE #WorkDate DATETIME, #WorkDateString varchar(100)
SET #WorkDate = DATEADD(DAY, DATEDIFF(DAY, '19000101', #WorkDate), '19000101')
SET #WorkDateString = 'SELECT MIN(' + CAST(#WorkDate as varchar(19)) + ') FROM ' + #DatabaseName + '.'
+ #SchemaName + '.' + #TableName + '_Hist'
Don't know if you looking to insert the #WorkDate into the select string but that's how you could accomplish that
It looks like the date field in this database is not stored as a DateTime value.
Instead of 19000101, use 1900-01-01. It is unable to recognize your date formate for your character string or your #WorkDate value is not valid.

SQL Server 2008 ALTER TABLE add column with specific column

Is there any way I can add a column to a table but I want the heading to be a date, and every new column added will have a column heading for the next day hence the
SET #date1 = #date1 + 1
What I want the table to look like is, where the date on top is a new column for each day the script loops:
StoreID StoreName 02/01/12 03/01/12 04/01/12
1234 Coles1 7512 8574
1235 Coles2 7210 8441
1236 Coles3 4845 5448
When I run the script I get the following error messages:
Msg 170, Level 15, State 1, Line 1
Line 1: Incorrect syntax near '#Column'.
Msg 170, Level 15, State 1, Line 1
Line 1: Incorrect syntax near '#Column'.
Here is my script:
DECLARE #date datetime
DECLARE #date1 datetime
DECLARE #date2 datetime
DECLARE #Column varchar(8)
SET #date = '02 Jan 2012'
SET #date1 = '02 Jan 2012'
SET #date2 = '08 Jan 2012'
SET #Column = CONVERT(VARCHAR(8), #date1, 3)
IF NOT EXISTS (SELECT * FROM sysobjects WHERE xtype = 'U' AND name = '#vl_temp_trans')
BEGIN
CREATE TABLE #vl_temp_trans
(StoreID INT,
StoreName VARCHAR(100),
#Column MONEY) ----> column name to be date "#Column)
END
WHILE (#date1 <= #date2)
BEGIN
SET #Column = CONVERT(VARCHAR(8), #date1, 3)
ALTER table #vl_temp_trans
ADD #Column MONEY ----> column name to be date "#Column"
Insert into #vl_temp_trans (storeID, storeName, #Column)
select storeId, storeName, TotalDailyTransactions
from daily_trans t1 (nolock)
full outer join outlets t2 (nolock) on t1.StoreID = t2.StoreID
where DailyEnd = #date1 + 1
SET #date1 = #date1 + 1
END
You can't do this without dynamic SQL. Here is a query that will get you the result you want. You are more than welcome to uncomment the --INTO #t bit, however it is unclear what you want to do with the #temporary table beyond that (if you tell us the end result, instead of "I want to add a column name as #column, maybe we can help with that too). In order to continue referencing that #t table, you'll need to continue using code within the same scope - meaning more dynamic SQL that is executed within the same sp_executesql call.
DECLARE
#start DATE = '2012-01-02',
#end DATE = '2012-01-08';
DECLARE
#sql NVARCHAR(MAX) = N'',
#colMax NVARCHAR(MAX) = N'',
#colNames NVARCHAR(MAX) = N'';
;WITH x(rn) AS ( SELECT TOP (DATEDIFF(DAY, #start, #end) + 1) ROW_NUMBER()
OVER (ORDER BY [object_id]) - 1 FROM sys.all_columns ),
y(d) AS ( SELECT CONVERT(CHAR(10), DATEADD(DAY, rn, #start)) FROM x
)
SELECT #colMax += N',' + CHAR(13) + CHAR(10)
+ QUOTENAME(d) + ' = SUM(CASE WHEN DailyEnd = '''
+ d + ''' THEN TotalDailyTransactions ELSE 0 END)',
#colNames += N',' + QUOTENAME(d) FROM y;
SET #sql = 'SELECT StoreID, StoreName, ' + STUFF(#colNames, 1, 1, '')
+ ' --INTO #t
FROM ( SELECT StoreID, StoreName, ' + STUFF(#colMax, 1, 1, '')
+ ' FROM dbo.daily_trans
WHERE DailyEnd >= ''' + CONVERT(CHAR(10), #start) + ''''
+ ' AND DailyEnd < ''' + CONVERT(CHAR(10), DATEADD(DAY, 1, #end)) + '''
GROUP BY StoreID, StoreName
UNION ALL SELECT StoreID, StoreName, ' + STUFF(#colMax, 1, 1, '')
+ ' FROM dbo.outlets
WHERE DailyEnd >= ''' + CONVERT(CHAR(10), #start) + ''''
+ ' AND DailyEnd < ''' + CONVERT(CHAR(10), DATEADD(DAY, 1, #end)) + '''
GROUP BY StoreID, StoreName) AS x';
PRINT #sql;
-- EXEC sp_executesql #sql;
I think the problem is that you can't use a variable to define a column name.
I used some of your code to test with. This first part executed fine.
DECLARE #date1 datetime
DECLARE #Column varchar(8)
SET #date1 = '02 Jan 2012'
SET #Column = CONVERT(VARCHAR(8), #date1, 3)
select #Column
But when I added the CREATE TABLE statement and executed all of it at once, then I got the same error you did.
CREATE TABLE #vl_temp_trans
(StoreID INT,
StoreName VARCHAR(100),
#Column MONEY) ----> column name to be date "#Column)
To do this you will need to build up the CREATE TABLE and ALTER TABLE statements as a string and then execute those using EXECUTE or sp_executesql. A search for "dynamic sql" will also give you some article that describe this too.
There is two things you need to do to execute this code...
Create dynamic sql make use of SP_ExecuteSQl
you need to make your temp table Gobal because when you create private temp table it remain in scope of dyanic sql sp only
have look to below code which is updated by me sure reslove your issue
DECLARE #date datetime
DECLARE #date1 datetime
DECLARE #date2 datetime
DECLARE #ColumnNAAME varchar(8)
Declare #Query NVARCHAR(1000)
DECLARE #ParmDefinition NVARCHAR(500);
SET #date = getdate()
SET #date1 = getdate()
SET #date2 = getdate()
SET #ColumnNAAME = CONVERT(VARCHAR(8), #date1, 3)
IF NOT EXISTS (SELECT * FROM sysobjects WHERE xtype = 'U' AND name = '#vl_temp_trans')
BEGIN
SET #ParmDefinition = N'#Column varchar(8)';
Set #Query = 'CREATE TABLE ##vl_temp_trans (StoreID INT, StoreName VARCHAR(100), ['+#ColumnNAAME+'] MONEY)'
EXECUTE sp_executesql #Query,#ParmDefinition,
#Column = #ColumnNAAME;
----> column name to be date "#Column)
SELECT * from ##vl_temp_trans
END
ELSE
BEGIN
SELECT * from ##vl_temp_trans
END