I have three parameters #startDate, #endDate, #name. The query I need to create a query that works like this.
If #startDate is not empty, WHERE #startDate <= time
If #endDate is not empty, add WHERE #endDate >= time
If #name is not empty, add WHERE name LIKE #name
That's what I want to do.... and this is the crappy code I've written.
ALTER blahblah...
#startDate varchar(10),
#endDate varchar(10),
#name varchar(7)
AS
BEGIN
SELECT *
FROM st.TB_RETENTION
WHERE
CASE WHEN #startDate != '' THEN #startDate <= time AND
CASE WHEN #endDate != '' THEN #endDate >= time AND
CASE WHEN #GameCode != '' THEN name LIKE #name
END
I think I'm quite close... but not sure how to add AND condition... Any advice for me? :(
You actually almost got it correct in your initial description:
where (#startDate is null or #startDate <= time)
and (#endDate is null or #endDate >= time)
and (#gameCode is null or name like #name)
Related
I have the following sample query within a stored procedure where the #StartDate, #EndDate and #ClientID parameters are all optional.
What is the best way to handle that within the query to ensure I get a result depending on whether 1 or many parameters have values?
select * from table
WHERE
StartDate >= #StartDate and
StartDate <= #EndDate and
CE.ClientID = #ClientID
For Example, someone could just enter a Start Date or just enter an End Date or select a particular ClientID or do a combination of all 3.
If you're willing to sacrifice a tiny amount of time on each execution, OPTION(RECOMPILE) will provide the performance equal to dynamic SQL but without all the perils of it.
select * from table
WHERE
(StartDate >= #StartDate or #StartDate is null) and
(StartDate <= #EndDate or #EndDate is null) and
(CE.ClientID = #ClientID or #ClientID is null)
option(recompile)
You can do something like this -
SELECT * FROM table
WHERE
(#StartDate IS NULL OR StartDate >= #StartDate) AND
(#EndDate IS NULL OR StartDate <= #EndDate) AND
(#ClientID IS NULL OR CE.ClientID = #ClientID)
The best way is to use dynamic SQL. Something like this:
declare #sql nvarchar(max);
set #sql = 'select * from table';
declare #where nvarchar(max);
set #where = (case when #StartDate is not null then ' and StartDate >= #StartDate' else '' end) +
(case when #EndDate is not null then ' and EndDate >= #EndDate' else '' end) +
(case when #ClientID is not null then ' and ClientID = #ClientID' else '' end);
set #where = stuff(#where, 1, 5, '');
set #sql = #sql + (case when len(#where) > 0 then ' where ' + #where' else '');
exec sp_executesql #sql,
N'#StartDate date, #EndDate date, #ClientId int',
#StartDate = #StartDate, #EndDate = #EndDate, #ClientId = ClientId;
The reason this is better is because each possible combination of inputs results in a different query. SQL Server can optimize the queries using appropriate indexes, and such optimization can be important when using optional parameters.
In SQL Server, I want to get days from date to date. Example: from 2015/12/28 to 2016/01/02, the result as
2015/12/28
2015/12/29
2015/12/30
2015/12/31
2016/01/01
2016/01/02
DECLARE #STARTDATE DATETIME = '2015-12-28'
DECLARE #ENDDATE DATETIME = '2016-01-02'
SELECT BETWEEN #STARTDATE AND #ENDDATE AS DAYS
Use CTE
DECLARE #STARTDATE DATE = '2015-12-28'
DECLARE #ENDDATE DATE = '2016-01-02'
;WITH CTE AS
(
SELECT #STARTDATE As dt
UNION ALL
SELECT DATEADD(D,1,dt) AS dt
FROM CTE
WHERE dt < #ENDDATE
)
SELECT * FROM CTE
You could build a calendar table, which would probably come in handy down the road. Or you could use a loop.
DECLARE #ENDDATE DATETIME = '2016-01-02'
DECLARE #DAY DATETIME = '2015-12-28'
WHILE #Day <= #ENDDATE
BEGIN
SELECT #DAY
SET #DAY = DATEADD(DD,1,#DAY)
END
Or for all of the days in one result set:
DECLARE #ENDDATE DATETIME = '2016-01-02'
DECLARE #DAY DATETIME = '2015-12-28'
DECLARE #TABLE TABLE (DATE DATETIME)
WHILE #Day <= #ENDDATE
BEGIN
INSERT #TABLE
VALUES (#DAY)
SET #DAY = DATEADD(DD,1,#DAY)
END
SELECT *
FROM #TABLE
You can specify the dates in your WHERE clause. For example, WHERE date >=#STARTDATE AND date <=#ENDDATE. That should return the full date in your results.
using Numbers table
select dateadd(day,n,startdate)
from numbers
where dateadd(day,n,startdate)<=enddate
order by n
Given:
CREATE PROCEDURE [dbo].[sp_func]
#StartDate DATE
, #EndDate DATE
AS
select * from [TRANS] where
(#StartDate IS NULL OR [TransDate] >= #StartDate) AND (#EndDate IS NULL OR [TransDate] <= #EndDate)
Both this:
declare #StartDate DATE = '2015-01-01'
declare #EndDate DATE = '2015-12-31'
exec dbo.sp_func #StartDate, #EndDate
And this:
declare #StartDate DATE = NULL
declare #EndDate DATE = NULL
exec dbo.sp_func #StartDate, #EndDate
...return rows as expected.
However, both of these calls return 0 rows:
exec dbo.sp_func '2015-01-01', '2015-12-31'
exec dbo.sp_func NULL, NULL
Am I fundamentally misunderstanding something here? As far as I can recall, I’ve always called sp’s passing dates like 'YYYY-MM-DD' with absolutely no issues.
Possibly related...this:
select CAST('2015-01-01' AS DATE), CAST('2015-12-31' AS DATE)
returns:
2015-01-01 2015-12-31
Whereas this:
exec dbo.sp_func CAST('2015-01-01' AS DATE), CAST('2015-12-31' AS DATE)
returns:
Incorrect syntax near '2015-01-01'.
I feel like I'm taking crazy pills.
I discovered the problem, it was stupidity.
Not shown in the example, I had other parameters in my production code, one of which was:
#JobClass VARCHAR(10) = 'PRODUCTION'
What I had been doing wrong in my test code was passing NULL to this, and incorrectly thinking that a passed NULL to this would instead default to 'PRODUCTION', whereas this defaulting only happens when the parameter is not passed at all. Which I knew of course. One of those days.
A couple of things , I would re-write the whole proc as below:
Procedure Definition
CREATE PROCEDURE [dbo].[usp_Proc] --<-- do not use sp_
#StartDate DATE = NULL
, #EndDate DATE = NULL
AS
BEGIN
SET NOCOUNT ON;
DECLARE #sql NVARCHAR(MAX);
SET #sql = N' select * from [TRANS] where 1 = 1 '
+ CASE WHEN #StartDate IS NOT NULL
THEN N' AND [TransDate] >= #StartDate' ELSE N' ' END
+ CASE WHEN #EndDate IS NOT NULL
THEN N' AND [TransDate] <= #EndDate ' ELSE N' ' END
Execute sp_executesql #sql
,N'#StartDate DATE,#EndDate DATE '
,#StartDate
,#EndDate
END
Execute Procedure
exec dbo.usp_Proc '20150101', '20151231' --<-- Pass date in ANSI format 'YYYYMMDD'
How about specifying the variable names and values like this:
EXECUTE dbo.sp_func #StartDate='2015-01-01',#EndDate='2015-12-31'
Works on my machine... :)
In SQL, I can use wildcard '%' on string and Select statement will show all the records like
select * from tablea where title like '%'
My question is what if both the start and end date are empty in the BETWEEN & AND function in Select statement.
Example
`select * from table where inputdate between '2014-01-01'` and '2014-01-31'
It works fine in this statement because there are start and end date.
What if there isn't any start and end date, and I want to show all the records?
select * from table where inputdate between '%' and '%' <--- not working.
Many thanks.
You can write your query in a way that inputdate column is evaluated against the value passed or if the no value is passed to #StartDate variable just pick earliest possible date,
I have select 1900-01-01 as the earliest date but depending on your column type you can pick a more appropriate substitute start and end dates.
DECLARE #StartDate DATE = '2014-01-01'
DECLARE #EndDate DATE = '2014-01-31'
select * from table
where inputdate >= COALESCE(#StartDate, '19000101')
and inputdate <= COALESCE(#EndDate , '99991231')
Dynamic SQL
Another better way of handling this kind of query with optional parameters will be using dynamic sql something like this...
DECLARE #StartDate DATE = '2014-01-01'
DECLARE #EndDate DATE = '2014-01-31'
DECLARE #Sql NVARCHAR(MAX);
SET #Sql = N'SELECT * FROM Table 1 = 1 '
+ CASE WHEN #StartDate IS NOT NULL THEN
N' AND inputdate >= #StartDate ' ELSE N' ' END
+ CASE WHEN #EndDate IS NOT NULL THEN
N' AND inputdate <= #EndDate ' ELSE N' ' END
Execute sp_executesql #Sql
,N'#StartDate DATE, #EndDate DATE'
,#StartDate
,#EndDate
wildcard can only be used on string, But since you mentioned the column is Date, you can do something better. Date min/max has been defined in almost all DBMS, IDK about the max but the min is usually January 1, 1753. so you can try between ' January 1, 1753' and 'date max'
SELECT * FROM table t
WHERE t.Date >= IIF(#FromDate IS NULL, t.Date, #FromDate)
AND t.Date <= IIF(#ToDate IS NULL, t.Date, #ToDate)
works fine.
i have a stored procedure like this:
ALTER procedure [dbo].[startandenddtime]
#startdate nvarchar(100)
as begin
declare #date3 nvarchar(100) = cast(CONVERT(varchar(100), #startdate + ' 16:59:59', 120) as datetime)
select date3 as startdate
end
If i pass my startdate as 2013-05-08 i am getting out put as :
but i want to get out put as 2013-05-08 16:59:59.000..so how i can convert this format
is this date time i can store in nvarchar varibale
Try like this
DECLARE #StartDate NVARCHAR(100)='2013-05-08'
SELECT CONVERT(VARCHAR,#StartDate+'16:59:59', 121)
MORE
SQL Fiddle
try this
ALTER procedure [dbo].[startandenddtime]
#startdate nvarchar(100)
as begin
declare #date3 nvarchar(100) = cast(CONVERT(VARCHAR(24),#startdate ,121)) as datetime)
select date3 as startdate
end
For more in details see this, http://technet.microsoft.com/en-us/library/ms187928.aspx
try this
Select cast(CONVERT(varchar(100), #startdate + ' 16:59:59') as date)
Or
Select cast(CONVERT(varchar(100), #startdate + ' 16:59:59') as datetime)
Try this :
Declare #dt varchar(20);
Declare #startdate varchar(20)='2013-05-08';
SET #dt= CONVERT(VARCHAR(20), CONVERT(datetime,#startdate+' 16:59:59'), 100)
Select #dt;
Just don't cast varchar value to datetime
edit: If you don't get what i meant in my comment:
convert(varchar, convert(datetime, #startdate + ' 16:59:59', 120), 120)