SQL Server - Converting to smalldatetime in dynamic SQL Statement - sql-server

The below dynamic SQL throws an error:
The conversion failed when converting character string to smalldatetime data type
My code:
DECLARE #pTimeStamp smalldatetime
SET #pTimeStamp = '2017-05-22 12:15:00'
DECLARE #SQLQuery AS NVARCHAR(4000)
Set #SQLQuery = N'Select *' +
' From SampleTable' +
' Where TimeStamp = ' + #pTimeStamp
EXECUTE sp_executesql #SQLQuery
I've also tried
Convert(smalldatetime, #pTimeStamp, 20)
as well as
CAST(#pTimeStamp AS smalldatetime)
but I only get other errors. I also tried declaring #pTimeStamp as varchar(50) and then converting but still got errors.
Doing something simple like:
DECLARE #pTimeStamp smalldatetime
SET #pTimeStamp = '2012-01-22 12:15:00'
Select *
From SampleTable
Where TimeStamp = #pTimeStamp
ran fine so I'm guessing it has to do with the dynamic SQL.
Please help....

The only truly safe formats for date/time literals in SQL Server, at least for datetime and smalldatetime, are: YYYYMMDD and YYYY-MM-DDThh:mm:ss[.nnn] - Bad habits to kick : mis-handling date / range queries - Aaron Bertrand
You are already using sp_executesql, so why not take advantage of its parameters?
declare #pTimeStamp smalldatetime;
declare #params nvarchar(4000);
declare #sqlquery nvarchar(4000);
set #pTimeStamp = '2017-05-22T12:15:00';
set #params = N'#pTimeStamp smalldatetime';
set #sqlquery = N'
select *
from SampleTable
where TimeStamp = #pTimeStamp';
execute sp_executesql #sqlquery, #params, #pTimeStamp;
rextester demo: http://rextester.com/FVC44260
Dynamic sql reference:
sp_executesql
The curse and blessings of dynamic SQL - Erland Sommarskog

You need to embed the timestamp in single quotes. Try:
Set #SQLQuery = N'Select *' +
' From SampleTable' +
' Where TimeStamp = ''' + #pTimeStamp + ''''

Related

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;

Issue with Dynamic SQL (Also: How to get SQL Lines from ExecuteNonQuery)

I am using Visual Studio, I'm trying to make a Insert statement using C# and Dynamic SQL.
SQL Command:
comando.CommandText = #"
declare #sql nvarchar(max);
set #sql = 'INSERT INTO ' + #curso + '(Data_Local, Deletado) VALUES ( ' + #date + ', 0)';
exec (#sql);
";
#curso is the Table Name, it's working, Data_Local is a Datetime value, which is not working, and Deletado is a bit value, which is working.
Declaring #curso:
comando.Parameters.Add("#curso", SqlDbType.NVarChar);
comando.Parameters["#curso"].Value = idCurso;
Declaring #date
comando.Parameters.Add("#date", SqlDbType.DateTime);
comando.Parameters["#date"].Value = dateTimePicker2.Value.Date;
Then after:
comando.ExecuteNonQuery();
The error message appears:
'Conversion failed when converting date and/or time from character
string.'
What should I do to read the value from the DateTimePicker, insert into the #date variable, and add it to the SQL Command properly?
Also, I have another doubt, where can I see how the SQL Command is sent? I need to see how the lines really are, how is the SQL Command without the variables, with the values instead.
Sorry if my issue is not explained very well, I'll keep trying to make it clear.
Edit:
I tried:
comando.CommandText = #"
declare #sql nvarchar(max);
set #sql = 'INSERT INTO ' + #curso + '(Data_Local, Deletado) VALUES ( ' + #date + ', 0)';
exec (#sql);
";
comando.Parameters.Add("#date", SqlDbType.NVarChar);
comando.Parameters["#date"].Value = "'" + dateTimePicker2.Value.Date + "'";
New error message:
'The conversion of a varchar data type to a datetime data type
resulted in an out-of-range value. The statement has been terminated.'
Edit. Thanks, solved.
Rather use a Stored Procedure, its awful if you going to use dynamic SQL in your c# application. Firstly because as a DBA, Adhoc queries like these are difficult to maintain, and secondly its easier to manage and also easier to apply to code.
1) Create a Stored Procedure
CREATE PROCEDURE Insert_Test
(
#curso VARCHAR(256),
#date VARCHAR(32)
)
AS
SET NOCOUNT ON
DECLARE #sql NVARCHAR(MAX)
IF ISDATE(#date) = 1 --check if its the correct date
BEGIN
SET #sql = 'INSERT INTO ' + #curso + '(Data_Local, Deletado) VALUES ( ''' + #date + ''', 0)'
EXEC (#sql)
END
2) In your c# code
string tbleName = "Test";
DateTime dte = DateTime.Now.ToString();
comando.ExecuteSqlCommand("exec Insert_Test #curso, #date",
new SqlParameter("curso", tbleName),
new SqlParameter("date", dte)
);

SQL Parameterised column names

I am trying to create a parameterised query for retrieving data back from a table
Essentially I have a table structure of
ID
nvarchar1
ntext
datetime1
datetime2
and I am trying to do a query like so that it selects all the data where the current date is greater than datetime1 and less than datetime2
SELECT
ID, nvarchar1,
ntext,
datetime1,
datetime2
FROM
TABLEName
WHERE
datetime1 >= #CurrentDate
AND datetime2 <= #CurrentDate
I want to make the columns parameters such as
#TableName, #CurrentDate, #StartDate, #EndDate
DECLARE #TableName NVARCHAR(100);
SET #TableName = '[Surveys].[dbo].[Table]'
DECLARE #CurrentDate DateTime;
SET #CurrentDate = GETDATE();
DECLARE #StartDate NVARCHAR(100);
SET #StartDate = 'datetime1'
DECLARE #EndDate NVARCHAR(100);
SET #EndDate = 'datetime2'
DECLARE #sql nvarchar(1000)
SET #sql = 'SELECT * FROM ' + #TableName + 'WHERE' + #EndDate + '>=' + #CurrentDate + 'AND' + #StartDatedatetime1 + '<=' + #CurrentDate
EXEC(#sql)
The data is going to be coming from a SP data source so I have no control of the column names etc. and when I create the SP Lists they automatically assign to a table column of that type so this is why I need to columns to be parameters.
Using the above code which I thought should work returns
Msg 241, Level 16, State 1, Line 14
Conversion failed when converting date and/or time from character string.
What am I doing wrong?
Try the below. As #GordonLinoff stated, you where missing the single quotes (') from around the #CurrentDate variable. Also, you where passing a DATETIME parameter in to the #sql variable which is an NVARCHAR data type. These are not implicitly converted, so the #CurrentDate variable needs to be converted to a NVARCHAR first:
DECLARE #sql nvarchar(1000)
SET #sql = 'SELECT * FROM ' + #TableName
+ ' WHERE ' + #EndDate + ' >= ''' + CONVERT(NVARCHAR(50), #CurrentDate,120)
+ ''' AND ' + #StartDate + ' <= ''' + CONVERT(NVARCHAR(50), #CurrentDate,120) + ''''
EXEC(#sql)
You are pretty close. I would construct the SQL for the table and then use parameters for the current date: This would be something like this:
SET #sql = '
SELECT *
FROM #TableName
WHERE datetime2 >= #CurrentDate AND datetime1 <= #CurrentDate';
SET #sql = REPLACE(#sql, '#TableName', #TableName);
exec sp_executesql #sql, N'#CurrentDate date', #CurrentDate = #CurrentDate;
Incidentally, the problem with your query is the lack of single quotes around the date constants.
EDIT:
You cannot substitute column or table names using parameters. I would write the code as:
SET #sql = '
SELECT *
FROM #TableName
WHERE #datetime2 >= #CurrentDate AND #datetime1 <= #CurrentDate';
SET #sql = REPLACE(#sql, '#TableName', #TableName);
SET #sql = REPLACE(#sql, '#datetime1', #DateTime1);
SET #sql = REPLACE(#sql, '#datetime2', '#DateTime2);
. . .
I use REPLACE() for this type of operation because the code is easier to understand and to maintain.

convert varchar parameter to datetime in sql procedure

Below is my procedure
create proc abc -- 'all','18','18','12/12/2015','','','inactive'
#JoinedDate varchar(100),
#LastLogin varchar(100),
#Location varchar(100),
#Status varchar(50)
as
declare #WhereCondition varchar(1000)
set #WhereCondition=' '
if #LastLogin !=''
set #WhereCondition= ' and u.UpdatedDate>=' + CAST(#LastLogin as datetime)
exec('select * from tableName where' + #WhereCondition)
When I am passing the parameter LastLogin it is giving me error as below:
Conversion failed when converting date and/or time from character string.
First of all capture the data in correct data type, If you are expecting a datetime value use the datetime data type for your variable.
Dont get values in varchar and then try to convert them to datetime(poor practice) , Also use parameterised dynamic sql do not concatenate variables into your dynamic sql (open doors for sql injection).
see below:
create proc abc -- 'all','18','18','12/12/2015','','','inactive'
#JoinedDate datetime,
#LastLogin datetime,
#Location varchar(100),
#Status varchar(50)
AS
BEGIN
SET NOCOUNT ON;
DECLARE #Sql NVARCHAR(MAX);
SET #Sql = N'select * from tableName where 1 = 1 '
+ CASE WHEN #LastLogin <> ''
THEN N' AND UpdatedDate >= #LastLogin' ELSE N'' END
Exec sp_executesql #Sql
,N'#LastLogin datetime'
,#LastLogin
END
You can't concatenate a Datetime datatype with a string.
EDITED:
Try this:
set #WhereCondition= ' and u.UpdatedDate>=CAST(''' + #LastLogin + ''' AS datetime)'
I got the solution, it is possible to pass datetime as varchar paramter to dynamic sql and convert it to datetime dynamically-
Below is the way -
set #WhereCondition= ' and u.UpdatedDate>=convert(datetime,''' + #LastLogin + ''', 110)'

sql server 2012: How do I deal with varbinary for #query variable in send_dbmail?

My intent is to monitor the cdc process through a stored proc managed by a sql agent job. I am looking to see if I have captured any data since the last time the job executed. The IntervalHours represents how many hours since the last batch ran. Here is the code snippet that is the setup for the notify/not-notify decision:
declare #FromLSN binary(10)
declare #ToLSN binary(10)
declare #BeginTime datetime
declare #EndTime datetime
declare #hasCurrentChanges int
declare #SendLowFloorMessage bit
select #BeginTime = dateadd(hh,-#IntervalHours,getdate())
SET #EndTime = GETDATE();
-- Map the time interval to a change data capture query range.
SET #FromLSN = [myInstance].sys.fn_cdc_map_time_to_lsn('smallest greater
than or equal', #BeginTime);
SET #ToLSN = [myInstance].sys.fn_cdc_map_time_to_lsn('largest less than
or equal', #EndTime);
-- Return the count of the net changes occurring within the query window.
SELECT #hasCurrentChanges = count(*) FROM
[myInstance].cdc.fn_cdc_get_net_changes_dbo_CRM_POSTran(#FromLSN, #ToLSN,
'all');
-- Here is the decision --
IF isnull(#hasCurrentChanges,0) <= #LowFloor
begin
set #SendLowFloorMessage = 1;
end
-- Here is the notification. This is where I would need the #qry to dub the value of #FromLSN and #ToLSN into the text of the query so it can execute. What do I need to cast the value to in order for this to succeed?
DECLARE #bdy nvarchar(1000);
DECLARE #sbj nvarchar(50)
DECLARE #MailRecipients VARCHAR(50)
DECLARE #qry nvarchar(max)
SET #MailRecipients = 'paula.ditallo#gmail.com'
--Send email with results of long-running jobs
EXEC msdb.dbo.sp_send_dbmail
#profile_name = #mailProfile
,#recipients = #MailRecipients
,#query = #qry
,#execute_query_database = 'InternalResource'
,#body = #bdy
,#subject = #sbj
,#attach_query_result_as_file = 1;
I am assuming that you have a good handle on sp_send_dbmail and just do not know how to create a dynamic TSQL for the #query using the varbinary data types. Here is one way to convert the data using the XML DOM.
Here is a reference to my website showing how to send an email with an attachment for 2008 R2.
http://craftydba.com/?p=1025.
This is almost the same for 2012 - Books On Line.
http://technet.microsoft.com/en-us/library/ms190307.aspx.
The sample code below takes two hex number and converts them into a call to the cdc.fn_cdc_get_net_changes_.
http://msdn.microsoft.com/en-us/library/bb522511.aspx
-- Sample data
DECLARE #from_lsn VARBINARY(10);
SET #from_lsn = 0x5BAA61E4C9B93F3F0682;
DECLARE #to_lsn VARBINARY(10);
SET #to_lsn = 0x5BAA61E4C9B93F3F0782;
-- Display the results
DECLARE #tsql VARCHAR(MAX);
SELECT #tsql =
'SELECT * FROM cdc.fn_cdc_get_net_changes_HR_Department(' +
char(39) + '0x' + CAST('' AS XML).value('xs:hexBinary(sql:variable("#from_lsn"))', 'VARCHAR(20)') + char(39) + ',' +
char(39) + '0x' + CAST('' AS XML).value('xs:hexBinary(sql:variable("#to_lsn"))', 'VARCHAR(20)') + char(39) + + ',' +
char(39) + 'all' + char(39) +');';
-- Show the data
PRINT #tsql
Here is the output from the snippet.
SELECT *
FROM cdc.fn_cdc_get_net_changes_HR_Department
('0x5BAA61E4C9B93F3F0682','0x5BAA61E4C9B93F3F0782','all');

Resources