SQL server SP : #Param 's with sometime NULL values - sql-server

I am very new to SQL Server Stored Procedures,
I am trying to create a SP that will give return a list of records in a table by filter via StartDate and EndDate , but there will be 'View All' Option so sometime those #Param might not contain any values.
Currently my SP is Like
CREATE PROCEDURE [dbo].[spGetBonusRun]
(
#StartDate as DATETIME,
#EndDate as DATETIME
)
AS
SELECT [Id]
,[StartDateTime]
,[EndDate]
,[Status]
FROM [Valt].[dbo].[BonusRun]
WHERE StartDateTime <= #StartDate AND EndDate >= #EndDate
How to active that ?

Try this:
WHERE (StartDateTime <= #StartDate OR #StartDate IS NULL) AND (EndDate >= #EndDate OR #EndDate IS NULL)
Hope it helps.
/Klaus

You can try something like this
CREATE PROCEDURE [dbo].[spGetBonusRun]
(
#StartDate as DATETIME,
#EndDate as DATETIME
)
AS
SELECT [Id]
,[StartDateTime]
,[EndDate]
,[Status]
FROM [Valt].[dbo].[BonusRun]
WHERE StartDateTime <= ISNULL(#StartDate, StartDateTime)
AND EndDate >= ISNULL(#EndDate, EndDate)
Note the use of ISNULL

Related

Querying null datetime field with parameters

I have a table on my database (SQL Server 2016):
ID (numeric(10,0), not null)
Price (numeric(12,2), not null)
StartDate (datetime, null)
EndDate (datetime, null)
(There are more fields, but this is enough to get the point across)
One particular record has 'NULL' values for StartDate and EndDate:
ID 15
Price 25
StartDate NULL
EndDate NULL
If I run the query:
SELECT * FROM [Table]
Then the record is return as expected
However the following query:
DECLARE #StartDate datetime = NULL
DECLARE #EndDate datetime = NULL
SELECT * FROM [Table]
WHERE StartDate = #StartDate AND EndDate = #EndDate
I get no records!
What am I missing?
The following does work, but it just 'feels' wrong!
DECLARE #StartDate datetime = NULL
DECLARE #EndDate datetime = NULL
SELECT * FROM [Table]
WHERE (StartDate = #StartDate OR (StartDate IS NULL AND #StartDate IS NULL))
AND (EndDate = #EndDate OR (EndDate IS NULL AND #EndDate IS NULL))
For context, the query will ultimately be run via a VB.Net application, but I'm getting this problem running the query via SSMS, so it's definitely a SQL issue.

Conditional Where clause in SQL query if one or both date range parameters are null

I am not sure if I am asking the right question here, but I will try to explain what I need. I need to write a SQL query with a #StartDate and an #EndDate parameter.
If both parameters have a value, then my where clause will need to include:
WHERE CAST(CreatedDate AS date) BETWEEN #StartDate AND #EndDate
If #EndDate is null, then it should be:
WHERE CAST(CreatedDate AS date) = #StartDate
If both or null then the date should not be a part of the WHERE clause at all.
I have tried a couple of things like:
DECLARE #StartDate varchar(20) = '12-02-2020'
DECLARE #EndDate varchar(20) = ''
SELECT *
FROM [dbo].[tbl_Support_Requests]
WHERE
CAST(CreatedDate AS date) >= ISNULL(#StartDate, CreatedDate)
AND CAST(CreatedDate AS date) <= ISNULL(#EndDate, CreatedDate)
and also:
DECLARE #StartDate varchar(20) = '12-02-2020'
DECLARE #EndDate varchar(20) = ''
SELECT *
FROM [dbo].[tbl_Support_Requests]
WHERE (#EndDate IS NULL
AND (CAST(CreatedDate AS date) >= #StartDate)
OR (#EndDate IS NOT NULL
AND CAST(CreatedDate AS date) >= #StartDate
AND CAST(CreatedDate AS date) <= #EndDate))
I am hoping there is a way to do this without the need for dynamic SQL. Any assistance is greatly appreciated.
Your first variant was quite close. Rather than using the proprietary ISNULL, we can use the SQL standard COALESCE instead. Which supports more than two arguments:
Declare #StartDate datetime2 = '20200212'
Declare #EndDate datetime2 = null
SELECT *
FROM [dbo].[tbl_Support_Requests]
WHERE
cast(CreatedDate as date) >= COALESCE(#StartDate, CreatedDate)
AND cast(CreatedDate as date) <= COALESCE(#EndDate, #StartDate, CreatedDate)
Logically, if #EndDate is null and #StartDate is not, this effectively becomes:
SELECT *
FROM [dbo].[tbl_Support_Requests]
WHERE
cast(CreatedDate as date) >= #StartDate
AND cast(CreatedDate as date) <= #StartDate
Which will only be true if CreatedDate is equal to #StartDate.
I am slightly concerned by the casts - if they're there because the type of CreatedDate isn't date, I'd strongly suggest that the table definition by updated. If, on the other hand, they're being used to "cast away" a time component, then the same operation should also be being done on the right hand side, inside the COALESCE, so that the values compare equal.
Don't cast your column, it'll be bad for performance. I also assume that your parameters are date data types, but that your column is actually a date and time (such as a datetime2), due to your casting. You can then just use a single ISNULL on the parameters, and then an OR for when they are both NULL:
WHERE (CreateDate >= #StartDate AND CreateDate < DATEADD(DAY,1,ISNULL(#EndDate,#StartDate))
OR (#StartDate IS NULL AND #EndDate IS NULL)
You'll probably want to put an OPTION (RECOMPILE) in there too, as the plan for when they both have NULL could be very different to when they don't.

Running data for 1 year dates in SQL Server

I have a procedure where I have calls data for each day. From this procedure I wrote another procedure to insert and update in the destination table.
We have a job which runs for every day. But now I need to run the data for past 1 year (each day).
Below are my parameters in insert update procedure - if I need to get data for 18th my parameters values are like below
,#StartDate datetime = '2020-04-18'
,#EndDate datetime = '2020-04-19'
,#SkillLevel varchar(10)='Total'
,#Region varchar(20) = 'US'
If I need to get data for 17th my parameters values are like below
,#StartDate datetime = '2020-04-17'
,#EndDate datetime = '2020-04-18'
,#SkillLevel varchar(10)='Total'
,#Region varchar(20) = 'US'
Like this to get data for last 1 year I need to run the code for 365 days which takes huge effort
Could anyone suggest how to pass dates individually for 1 year with some loop.
Try this:
DECLARE #DataSource TABLE
(
[StartDate] DATE
);
DECLARE #BegDate DATE
,#EndDate DATE;
SELECT #BegDate = '2020-01-01'
,#EndDate = '2020-12-31';
DECLARE #EndNumber BIGINT;
SELECT #EndNumber = DATEDIFF(DAY, #BegDate, #EndDate);
INSERT INTO #DataSource ([StartDate])
SELECT TOP (#EndNumber) DATEADD(DAY, ROW_NUMBER() OVER(ORDER BY T1.[number])-1, #BegDate)
FROM master..spt_values T1
CROSS JOIN master..spt_values T2;
WHILE EXISTS(SELECT 1 FROM #DataSource)
BEGIN;
SELECT TOP 1 #BegDate = [StartDate]
,#EndDate = DATEADD(DAY, 1, [StartDate])
FROM #DataSource;
--
EXEC [stored_precedure] #StartDate = #BegDate
,#EndDate = #EndDate
,#SkillLevel ='Total'
,#Region = 'ES'
--
DELETE FROM #DataSource
WHERE [StartDate] = #BegDate;
END;

How to create date table with given datetime range?

I'm trying to create a table for calendar.But sql server stops at '2000-01-11 17:45'. How can i do create dates adding 15 minutes until 2050
Create Table Calendar
(id int IDENTITY(1,1) Primary key,CalendarDate DATETIME)
Declare #beginDate DATETIME, #endDate DATETIME
Select #beginDate = '2000-01-01 17:45', #endDate = '2050-01-01 09:00'
While #beginDate <= #endDate
Begin
Insert Into dbo.Calendar(CalendarDate)
Select
#beginDate As CalendarDate
Set #beginDate = DateAdd(MINUTE, 15, #beginDate)
End
Your current syntax suggest SQL Server, so i would try with recursive CTE :
with cte as (
select #beginDate as st
union all
select DATEADD(MINUTE, 15, st)
from cte
where st < #endDate
)
Insert Into dbo.Calendar(CalendarDate)
select st as CalendarDate
from cte
option (maxrecursion 0);

Get monthly attendance for an employee

I have a query that a guy helped here in developing which gives fine result. I want to use this query in a function which later I want to use in a procedure.
CREATE FUNCTION [dbo].[fnGetWorkedDays] (#StartDate datetime, #EndDate datetime)
RETURNS int
AS
BEGIN
DECLARE #dateFrom datetime
DECLARE #dateTo datetime
SET #dateFrom = #StartDate
SET #dateTo = #EndDate
DECLARE #DAYSWORKED INT
SELECT #DAYSWORKED = (
SELECT EmpId, COUNT(*) as DaysWorked
FROM
(
SELECT DISTINCT EmpId,CAST(TimeIn AS DATE) AS [Date]
FROM myTable
WHERE TimeIn IS NOT NULL
AND CAST(TimeIn AS DATE) BETWEEN #StartDate AND #EndDate
)T
GROUP BY EmpId
ORDER BY EmpId)
RETURN ISNULL(#DAYSWORKED,0)
END
The very first error I am getting is that
Msg 1033, Level 15, State 1, Procedure fnGetWorkedDays, Line 24
The ORDER BY clause is invalid in views, inline functions, derived tables, subqueries, and common table expressions, unless TOP, OFFSET or FOR XML is also specified.
I removed ORDER BY then I got another error says
Msg 116, Level 16, State 1, Procedure fnGetWorkedDays, Line 25
Only one expression can be specified in the select list when the subquery is not introduced with EXISTS.
I suggest you to go though this to understand more on table valued functions vs scalar valued function Difference between scalar, table-valued, and aggregate functions in SQL server?
Regarding your scenario, you should be writing a table values function for this like following.
CREATE FUNCTION [dbo].[fnGetWorkedDays]
(
#StartDate AS DATETIME,
#EndDate datetime
)
RETURNS TABLE
AS
RETURN
SELECT EmpId, COUNT(*) as DaysWorked
FROM
(
SELECT DISTINCT EmpId,CAST(TimeIn AS DATE) AS [Date]
FROM myTable
WHERE TimeIn IS NOT NULL
AND CAST(TimeIn AS DATE) BETWEEN #StartDate AND #EndDate
)T
GROUP BY EmpId
To use the function you can write your queries like following.
DECLARE #StartDate datetime
DECLARE #EndDate datetime
SET #StartDate = '2018-01-01'
SET #EndDate = '2018-01-31'
select * from [dbo].[fnGetWorkedDays](#StartDate,#EndDate)
If you want this to work as a scalar value function, in that case you need to pass EmpId as parameter like following.
CREATE FUNCTION [dbo].[fnGetWorkedDaysEmpWise]
(
#StartDate AS DATETIME,
#EndDate datetime,
#EmpId INT
)
RETURNS INT
AS
BEGIN
DECLARE #RetunCount INT
SELECT #RetunCount = COUNT(DISTINCT CAST(TimeIn AS DATE))
FROM myTable
WHERE TimeIn IS NOT NULL
AND CAST(TimeIn AS DATE) BETWEEN #StartDate AND #EndDate
AND EmpID=#EmpId
RETURN #RetunCount
END
And you can use it directly in your select clause like following.
DECLARE #StartDate datetime
DECLARE #EndDate datetime
SET #StartDate = '2018-01-01'
SET #EndDate = '2018-01-31'
SELECT [dbo].[fnGetWorkedDaysEmpWise](#StartDate,#EndDate,1)
Is this what you are looking for .?
CREATE FUNCTION [dbo].[fnGetWorkedDays] (#StartDate datetime, #EndDate datetime)
RETURNS #DaysWorked TABLE
(
Empid Int,
DaysWorked Int
)
AS
BEGIN
insert into #DaysWorked (Empid,DaysWorked)
SELECT EmpId, COUNT(*) as DaysWorked
FROM
(
SELECT DISTINCT EmpId,CAST(TimeIn AS DATE) AS [Date]
FROM myTable
WHERE TimeIn IS NOT NULL
AND CAST(TimeIn AS DATE) BETWEEN #StartDate AND #EndDate
)T
GROUP BY EmpId
ORDER BY EmpId
RETURN
END
select * from [fnGetWorkedDays]('2018-01-01','2018-01-31')

Resources