I have column of type of datetime, that I am using in my stored procedure by declaring the two local variables as #From datetime and #To datetime, but no matter what I do I get the error or it simply run the stored procedure without returning any records(completely blank).
set #mySql ='
select * from abc where (MyDATE between '''+ cast(#From as datetime) +''' and '''+ cast(#To as datetime)+''')'
The only "correct" way to do this is to preserve them as parameters inside the dynamic SQL. For example:
set #mySql =N'select * from abc where MyDATE between #from and #to';
exec sp_executesql #mySql, N'#from datetime, #to datetime', #fromOuter, #toOuter;
This keeps them correctly typed in the dynamic code, and avoids both formatting concerns and SQL injection risks. Note that the names inside and outside the dynamic code do not need to match, as shown in the example above (#from and #to are the names in the dynamic code; #fromOuter and #toOuter are the names in the calling code).
Note that it doesn't matter if you pass in more parameters than you actually use (this would be pretty normal for a dynamic filtering method).
Try to keep your data in variables of the appropriate type, whenever possible.
For instance, here you can do:
--#From and #To are declared previously as datetimes
set #mySql ='select * from abc where (MyDATE between #From and #To)'
--Other code that constructs/works on #mySQL
--Finally, run the dynamic sql:
EXEC sp_executesql #mySql,
'#From datetime,#To datetime`,
#From,
#To
And everything should work beautifully because you're not forcing back and forth between strings and datetimes, and its those conversions that introduce the opportunity to have formatting issues.
the issue here is that when you are building the Dynamic SQL, you are looking to cast your parameters as DateTime.
What you should actually do is avoid the use of casting. Set the Parameters as date time and store required values before you use them to build your dynamic SQL Statement.
Related
I'm calling a stored procedure and passing in 2 dates as parameters from my windows application. Its returning all rows rather than 2 rows that I'm expecting.
The stored procedure is:
ALTER procedure [dbo].[Get_Entries]
#Start_Date datetime=null,
#End_Date datetime=null
as
begin
SELECT *
FROM MyTable
WHERE (MyTable.Date BETWEEN #Start_Date AND #End_Date
OR (#Start_Date IS NULL AND #End_Date IS NULL))
ORDER BY MyTable.Date desc
end
The following sp_executesql query returns all rows:
exec sp_executesql N'Get_Entries', N'#Start_Date datetime, #End_Date datetime',
#Start_Date='2015-06-06 11:35:06.437',
#End_Date='2015-07-06 11:35:06.437'
However if I run the stored procedure manually from Management Studio I get the expected 2 rows:
USE [MyDatabase]
GO
DECLARE #return_value int
EXEC #return_value = [dbo].[Get_Entries]
#Start_Date = N'2015-06-06 11:35:06.437',
#End_Date = N'2015-07-06 11:35:06.437'
SELECT 'Return Value' = #return_value
GO
Any ideas why sp_executesql isn't returning the filtered list? Its returning all rows.
The way to solve this is to use the (slightly adapted) ISO-8601 date format that is supported by SQL Server - this format works always - regardless of your SQL Server language and dateformat settings.
The ISO-8601 format is supported by SQL Server comes in two flavors:
YYYYMMDD for just dates (no time portion); note here: no dashes!, that's very important! YYYY-MM-DD is NOT independent of the dateformat settings in your SQL Server and will NOT work in all situations!
or:
YYYY-MM-DDTHH:MM:SS for dates and times - note here: this format has dashes (but they can be omitted), and a fixed T as delimiter between the date and time portion of your DATETIME.
This is valid for SQL Server 2000 and newer.
If you use SQL Server 2008 or newer and the DATE datatype (only DATE - not DATETIME!), then you can indeed also use the YYYY-MM-DD format and that will work, too, with any settings in your SQL Server.
Don't ask me why this whole topic is so tricky and somewhat confusing - that's just the way it is. But with the YYYYMMDD format, you should be fine for any version of SQL Server and for any language and dateformat setting in your SQL Server.
My recommendation for SQL Server 2008 and newer is to use DATE if you only need the date portion, and DATETIME2(n) when you need both date and time. You should try to start phasing out the DATETIME datatype if ever possible
In your case values are not passed to stored procedure and it runs with default values.
If you remove the default values in your stored procedure you will get following error:
Procedure or function 'Get_Entries' expects parameter '#Start_Date', which was not supplied.
sp_executesql is used to make a code reusable. Using sp_executesql to execute stored procedure gives no benefit.
sp_executesql executes a Transact-SQL statement or batch that can be
reused many times, or that has been built dynamically.
You can find a way around using code given below
Declare #statement nvarchar(max)
set #statement = N'Get_Entries ''2010-06-06 11:35:06.437'', ''2015-07-06 11:35:06.437'''
exec sp_executesql #statement
Let's take a look at your sp_executesql statement:
exec sp_executesql N'Get_Entries',
N'#Start_Date datetime, #End_Date datetime',
#Start_Date='2015-06-06 11:35:06.437',
#End_Date='2015-07-06 11:35:06.437'
This query tells SQL Server to execute the following query:
'Get_Entries'
The way you are invoking sp_executesql says the query uses the following parameters:
'#Start_Date datetime,#End_Date datetime'
However, the query text string 'Get_Entries' does not use these parameters. Therefore, SQL Server will not put the parameters into the query. The result query is equivalent to the following code:
exec Get_Entries
Without specifying any parameters, your stored procedure will return all rows.
To use the parameters, you need to place them in your dynamic SQL query like below. I renamed the dynamic SQL parameters to make it clearer where they are used in the query:
exec sp_executesql N'Get_Entries #Start_Date = #StartDateParm, #End_Date = #EndDateParm',
N'#StartDateParm datetime, #EndDateParm datetime',
#StartDateParm='2015-06-06 11:35:06.437',
#EndDateParm='2015-07-06 11:35:06.437'
Note that you don't need to put a stored procedure call in a call to sp_executesql. It is more efficient to call the procedure directly.
I am trying to rename a table in SQL Server 2008 R2 using the code below;
declare #date varchar(8)
set #date = convert( varchar(8), getdate(), 112)
exec sp_rename 'LM_SM_Billing_and_Send_Data', 'LM_SM_Billing_and_Send_Data_#date'
My intention is to rename the table with the current date appended.
select convert( varchar(8), getdate(), 112)
returns 20141219
but when I run the rename it names the table;
LM_SM_Billing_and_Send_Data_#date
instead of inserting the date
I'm wondering if it is possible to have it rename to;
LM_SM_Billing_and_Send_Data_20141219
by using the variable in the table name.
I've been googling quite a bit and things seem to point to using dynamic SQL, but I've never used it and not sure what the syntax would be to get the results I am looking for.
The issue you've ran into here, as John Saunders pointed out in his comment, SQL won't substitute the value of your variable into your parameter. (String interpolation)
Another issue you might run into, when trying to work around this problem, is concatenating in the procedure call. The following will also not work.
exec sp_rename 'LM_SM_Billing_and_Send_Data', 'LM_SM_Billing_and_Send_Data_' + #date
The reason the above will also error, is because a parameter can be either a variable, or a constant, not an expression as the above shows. If we declare #myNewName, and set the desired value into that variable, we can then pass that to the procedure.
Give this a try:
declare #date varchar(8)
set #date = convert( varchar(8), getdate(), 112)
declare #myNewName varchar(255) = 'LM_SM_Billing_and_Send_Data_' + #date
exec sp_rename 'LM_SM_Billing_and_Send_Data', #myNewName
This may be a good reference as one continues to work with SQL parameters: http://msdn.microsoft.com/en-us/library/ms189260(v=sql.105).aspx
Use Dynamic Sql to append the variable to the new table name.
Use select * into syntax to copy the data from new old table to new table this part has to be done dynamically.
Then finally drop the old table
declare #date varchar(8),
set #date = convert( varchar(8), getdate(), 112)
set #sql ='select * into LM_SM_Billing_and_Send_Data_'+#date+'
from LM_SM_Billing_and_Send_Data'
exec sp_executesql #sql
Drop table LM_SM_Billing_and_Send_Data
I don't get any errors when I do this, but it creates a table called "dbo.#tablename" in my database when i really want is for it to create the value that i am passing as the parameter in the exec procedure as the tablename. What am i doing wrong. Here is my update procedure script. Maybe i can change so so that it does create the value as the table name.
Here is what i have so far:
ALTER PROCEDURE [dbo].[Load_Negatives]
-- Add the parameters for the stored procedure here
#TABLENAME SYSNAME,
#AuditPeriodStartDate datetime,
#AuditPeriodEndDate datetime
AS
BEGIN
SET NOCOUNT ON;
Select
Location,
Customer,
Transaction_date
into
dbo.[#TABLENAME]
from dbo.CustomerHistory (nolock)
where
[Transaction_date] between #AuditPeriodStartDate and #AuditPeriodEndDate
END
Table names cannot be parametrised. Therefore, you need to build your SQL statement dynamically, incorporating the name into the dynamic script.
To minimise the risk of SQL injection, use the QUOTENAME system function with the #TABLENAME value and introduce parametrisation to your dynamic query to pass the other two parameters of the stored procedure:
ALTER PROCEDURE [dbo].[Load_Negatives]
#TABLENAME SYSNAME,
#AuditPeriodStartDate datetime,
#AuditPeriodEndDate datetime
AS
BEGIN
SET NOCOUNT ON;
DECLARE #sql nvarchar(max);
SET #sql = N'Select
Location,
Customer,
Transaction_date
into
dbo.' + QUOTENAME(#TABLENAME) + N'
from dbo.CustomerHistory (nolock)
where
[Transaction_date] between #AuditPeriodStartDate and #AuditPeriodEndDate'
;
EXECUTE sp_executesql
#sql,
N'#AuditPeriodStartDate datetime, #AuditPeriodEndDate datetime',
#AuditPeriodStartDate, #AuditPeriodEndDate
;
END
Basically, the dynamic query looks almost exactly the same as your current query. The only difference is that the table name is added as the result of QUOTENAME(#TABLENAME). The datetime parameters of the dynamic query happen to have same names as the corresponding parameters of the stored procedure but that is not mandatory.
The EXECUTE sp_executesql statement passes the datetime arguments to the dynamic query and then executes it.
One other note is about your use of the BETWEEN predicate with datetime values. If Transaction_date includes timestamps with non-zero time portions, it would be much better to specify the range in this form:
[Transaction_date] >= #AuditPeriodStartDate
and
[Transaction_date] < #AuditPeriodEndDate
That way you can be sure the results will include only relevant values. More information can be found in this blog article:
What do BETWEEN and the devil have in common?
When I am trying to carry out following statement from Management Studio, it is executed successfully -
exec [sp_GetAllBillsForDate] '03/06/2012','03/06/2012'
But when I change it to
exec [sp_GetAllBillsForDate] getdate(), getdate()
it is generating error
Incorrect syntax near ')'.
whats wrong with this?
Thanks for sharing your time.
The answer is that you can't pass a function as an argument to a stored procedure parameter.
If you just want to use the current date/time when you don't want to pass values in, why not make those parameters optional by supplying a default value inside the procedure? This will save you from having to type it, declare local variables, and even more importantly from passing those useless tokens from client applications.
You should also avoid ambiguous date formats like m/d/y and d/m/y. If it wasn't March right now, I'd have no idea whether you meant March 6 or June 3. And when you run your code somewhere with different regional or language settings, SQL Server might get it wrong too. State it unambiguously in a clear format (e.g. YYYYMMDD) immune to language, region or human perception issues.
Anyway here is the procedure with optional parameters:
ALTER PROCEDURE dbo.sp_GetAllBillsForDate -- sp_ is a horrible prefix, by the way *
#date1 DATETIME = GETDATE(),
#date2 DATETIME = GETDATE()
AS
BEGIN
SET NOCOUNT ON;
...
END
GO
Now the code for a hard-coded date:
EXEC dbo.sp_GetAllBillsForDate #date1 = '20120306', #date2 = '20120306';
And to get todays:
EXEC dbo.sp_GetAllBillsForDate;
(Also a good idea to explicitly name your parameters. Then you don't have to worry about the parameter order changing. And also to always use the schema prefix when referencing or creating all objects.)
http://www.sqlmag.com/article/tsql3/should-i-use-the-sp_-prefix-for-procedure-names-
Try to pass through variable..
DECLARE #date1 DATETIME
,#date2 DATETIME
SELECT #date1 = GETDATE()
,#date2 = GETDATE()
EXEC [sp_GetAllBillsForDate] #date1, #date2
I need to insert a datetime value into datetime column in SQL Server 2005
I am passing DateTime variable from the .aspx page
Which needs to be inserted in the column.
Example:
Table(date datetime)
#sql = 'insert into Table (date) values('+#datetime+')'
exec(#sql)
getting conversion failed message.
Any idea how to do this.
Very Urgent.
Thanks.
You need string delimiters - in T-SQL this is doubled-up single quotes.
SET #sql = 'insert into Table (date) values('''+#datetime+''')'
exec(#sql)
However it still might fail, depending on the format of the string. Any reason you're building a SQL string, prone to SQL injection, instead of just saying:
INSERT Table(date) SELECT #datetime;
?
Add escaped single quotes around the datetime value. Normally they are passed as strings.
See if this works:
#sql = 'insert into Table (date) values('''+#datetime+''')'
exec(#sql)
Make sure your query/stored procedure are expecting to receive the parameter as a datetime variable (not varchar(20), or anything else like that), and make sure your ASP.Net code is passing the value as a datetime value also.
Basically, for best datetime handling, convert them from strings into datetimes as early as possible when accepting them as input (e.g. convert them in an appropriate event in your code behind in ASP.NET), keep them as datetimes whenever passing them to/from the database, and fromat them back as strings as late as possible when outputting them (e.g. in view code for asp.net mvc, or when assigning to the Text property of an ASP.Net control)
Besides the other suggestions with delimiters and parenthesis mismatches, Date is a reserved keyword, use [Date] instead.
Try making this small change to your sql statement
#sql = "insert into Table (date) values ('"+ #datetime + "')"
Declare #datetime datetime
Set #datetime=GetDate()
Declare #sql nvarchar(1000)
Declare #param nvarchar(1000)
Set #param='#datetime datetime'
SET #sql = 'insert into Table (date) values(#datetime)'
exec sp_executesql #sql,#param,#datetime
you have to learn the sql injection for dynamic queries.