SQL Server Stored Procedure - Generate Where clause - sql-server

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

Utilising optional parameters in where clause

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.

How to get days from date to date in SQL Server?

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

DATE parameter passed as 'YYYY-MM-DD' not being properly evaluated by a stored procedure?

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... :)

SQL select between dates, but show all when start and end date are empty

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.

converting date time format in sql

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)

Resources