How to compare time slot in SQL Server? - sql-server

I have a table [pricelist]
startHour
endHour
Price
and another table that contains the [actualuse]
startDate
endDate
user
My data
pricelist:
startHour | endHour | price
----------------------------
00:00 | 07:59 | 10
08:00 | 15:59 | 20
16:00 | 23:59 | 5
actualUse:
startDate | endDate | jobId
-------------------------------------------
12/10/2014 08:30 | 12/10/2014 15:20| 1
12/10/2014 07:30 | 12/10/2014 18:20| 2
12/10/2014 07:30 | 13/10/2014 16:20| 3
12/10/2014 09:30 | 13/10/2014 00:20| 4
I try to get for every gob all rows in pricelist the are belong to. For example for jobId 1 I will get
startDate | endDate | jobId |price
---------------------------------------------------
12/10/2014 08:30 | 12/10/2014 15:20| 1 |20
for jobId 2
startDate | endDate | jobId |price
---------------------------------------------------
12/10/2014 07:30 | 12/10/2014 07:59| 2 |10
12/10/2014 08:00 | 12/10/2014 15:59| 2 |20
12/10/2014 16:00 | 12/10/2014 18:20| 2 |5
for jobId 3
startDate | endDate | jobId |price
---------------------------------------------------
12/10/2014 07:30 | 12/10/2014 07:59| 3 |10
12/10/2014 08:00 | 12/10/2014 15:59| 3 |20
12/10/2014 16:00 | 12/10/2014 23:59| 3 |5
13/10/2014 00:00 | 13/10/2014 07:59| 3 |10
13/10/2014 08:00 | 13/10/2014 15:59| 3 |20
13/10/2014 16:00 | 13/10/2014 16:20| 3 |5

Here is a possible working solution. I know the cursor is a bit ugly but I had to create another table with every possibles dates between the date ranges. You might be able to refactor some date computation too (I assumed you were working with TIME datatype)
/*
create table pricelist
(
startHour time,
endHour time,
price decimal(18,2)
)
create table actualuse
(
startDate datetime,
endDate datetime,
jobId int
)
insert pricelist values
('00:00','07:59',10),
('08:00','15:59',20),
('16:00','23:59',5)
set dateformat dmy
insert actualuse values
('12/10/2014 08:30','12/10/2014 15:20',1),
('12/10/2014 07:30','12/10/2014 18:20',2),
('12/10/2014 07:30','13/10/2014 16:20',3),
('12/10/2014 09:30','13/10/2014 00:20',4)
*/
BEGIN TRY DROP TABLE #actualUseDays END TRY
BEGIN CATCH END CATCH
CREATE TABLE #actualUseDays (
startDate DATETIME
,endDate DATETIME
,jobId INT
)
DECLARE #startDate DATETIME
,#endDate DATETIME
,#jobId INT;
DECLARE cur CURSOR FORWARD_ONLY FOR SELECT * FROM actualuse
OPEN cur;
FETCH NEXT FROM cur INTO #startDate ,#endDate ,#jobId
WHILE ##FETCH_STATUS = 0
BEGIN
INSERT #actualUseDays
SELECT #startDate
,iif(CAST(#endDate AS DATE) <> CAST(#startDate AS DATE), DATEADD(day, DATEDIFF(day, '19000101', cast(#startDate AS DATE)), CAST(CAST('23:59:59' AS TIME) AS
DATETIME2(7))), #endDate)
,#jobId
UNION
SELECT CAST(DATEADD(DAY, number + 1, #startDate) AS DATE) [Date]
,iif(CAST(#endDate AS DATE) <> CAST(DATEADD(DAY, number + 1, #startDate) AS DATE), DATEADD(day, DATEDIFF(day, '19000101', CAST(DATEADD(DAY, number + 1,
#startDate) AS DATE)), CAST(CAST('23:59:59' AS TIME) AS DATETIME2(7))), #endDate)
,#jobId
FROM master..spt_values
WHERE type = 'P'
AND DATEADD(DAY, number + 1, CAST(#startDate AS DATE)) < #endDate
FETCH NEXT FROM cur INTO #startDate ,#endDate ,#jobId
END
CLOSE cur;
DEALLOCATE cur;
/*
#actualUseDays now contains :
startDate endDate jobId
----------------------- ----------------------- -----------
2014-10-12 08:30:00.000 2014-10-12 15:20:00.000 1
2014-10-12 07:30:00.000 2014-10-12 18:20:00.000 2
2014-10-12 07:30:00.000 2014-10-12 23:59:59.000 3
2014-10-13 00:00:00.000 2014-10-13 16:20:00.000 3
2014-10-12 09:30:00.000 2014-10-12 23:59:59.000 4
2014-10-13 00:00:00.000 2014-10-13 00:20:00.000 4
*/
SELECT iif(CAST(a.startDate AS TIME) > p.startHour, startDate, DATEADD(day, DATEDIFF(day, '19000101', CAST(startDate AS DATE)), CAST(startHour AS DATETIME2(7)))) AS
startDate
,iif(CAST(a.endDate AS TIME) < p.endHour, endDate, DATEADD(day, DATEDIFF(day, '19000101', CAST(endDate AS DATE)), CAST(endHour AS DATETIME2(7)))) AS endDate
,jobId
,price
FROM #actualUseDays a
INNER JOIN pricelist p
ON CAST(a.startDate AS TIME) <= p.endHour
AND CAST(a.endDate AS TIME) >= p.startHour
ORDER BY jobId
,iif(CAST(a.startDate AS TIME) > p.startHour, startDate, DATEADD(day, DATEDIFF(day, '19000101', CAST(startDate AS DATE)), CAST(startHour AS DATETIME2(7))))
Results :
startDate endDate jobId price
--------------------------- --------------------------- ----------- ---------------------------------------
2014-10-12 08:30:00.0000000 2014-10-12 15:20:00.0000000 1 20.00
2014-10-12 07:30:00.0000000 2014-10-12 07:59:00.0000000 2 10.00
2014-10-12 08:00:00.0000000 2014-10-12 15:59:00.0000000 2 20.00
2014-10-12 16:00:00.0000000 2014-10-12 18:20:00.0000000 2 5.00
2014-10-12 07:30:00.0000000 2014-10-12 07:59:00.0000000 3 10.00
2014-10-12 08:00:00.0000000 2014-10-12 15:59:00.0000000 3 20.00
2014-10-12 16:00:00.0000000 2014-10-12 23:59:00.0000000 3 5.00
2014-10-13 00:00:00.0000000 2014-10-13 07:59:00.0000000 3 10.00
2014-10-13 08:00:00.0000000 2014-10-13 15:59:00.0000000 3 20.00
2014-10-13 16:00:00.0000000 2014-10-13 16:20:00.0000000 3 5.00
2014-10-12 09:30:00.0000000 2014-10-12 15:59:00.0000000 4 20.00
2014-10-12 16:00:00.0000000 2014-10-12 23:59:00.0000000 4 5.00
2014-10-13 00:00:00.0000000 2014-10-13 00:20:00.0000000 4 10.00

Related

SQL Server min max with intermediate record

I am sorry if this question has been answered before, but I cannot find it. Perhaps of my bad keywords.
I have this table:
CREATE TABLE test1
(
Employee VARCHAR(10),
Band VARCHAR(10),
StartDate DATE,
EndDate DATE
)
INSERT INTO test1
VALUES ('Emp1', 'Band1', '2009-01-01', '2010-12-31'),
('Emp1', 'Band1', '2011-01-01', '2012-12-31'),
('Emp1', 'Band1', '2013-01-01', '2013-08-31'),
('Emp1', 'Band2', '2013-09-01', '2013-12-31'),
('Emp1', 'Band2', '2014-01-01', '2014-06-30'),
('Emp1', 'Band1', '2014-07-01', '2014-12-31'),
('Emp1', 'Band1', '2015-01-01', '2018-08-31'),
('Emp2', 'Band1', '2012-01-01', '2014-12-31'),
('Emp2', 'Band1', '2015-01-01', '2018-03-31')
Results in this table:
Employee Band StartDate EndDate
----------------------------------------
Emp1 Band1 2009-01-01 2010-12-31
Emp1 Band1 2011-01-01 2012-12-31
Emp1 Band1 2013-01-01 2013-08-31
Emp1 Band2 2013-09-01 2013-12-31
Emp1 Band2 2014-01-01 2014-06-30
Emp1 Band1 2014-07-01 2014-12-31
Emp1 Band1 2015-01-01 2018-08-31
Emp2 Band1 2012-01-01 2014-12-31
Emp2 Band1 2015-01-01 2018-03-31
What I want to create is a result table grouping each employee with the band and the minimum start date and maximum end date, but when an intermediate record (band) exist in the middle between the similar band, the end date should be capped and the start date of the next group in similar band should reset again.
Employee Band StartDate EndDate
----------------------------------------
Emp1 Band1 2009-01-01 2013-08-31
Emp1 Band2 2013-09-01 2014-06-30
Emp1 Band1 2014-07-01 2018-08-31
Emp2 Band1 2012-01-01 2018-03-31
I have tried CTE to get the max and min of each band and compare it with the original table, but I still fail. I also tried using lead and lag but still fail.
Nice to have
Supposed the second record's EndDate is 2012-02-01, I prefer the result is still one record for the first Band1 group.
Employee Band StartDate EndDate
----------------------------------------
Emp1 Band1 2009-01-01 2013-08-31
With each row of the result only differing in Band, I would able to figure out how long an employee has stayed in a certain band before moving to other band (different band).
But it is something nice to have.
Apparently you want to group rows whenever an employee changes band. This is straight forward with window functions. The following solution adds a "change" flag to rows whenever the band changes. Be advised that it ignores gaps. Add DATEDIFF check to the case statement to find the actual amount of time the person was associated with a band:
DECLARE #test1 TABLE(
Employee VARCHAR(10),
Band VARCHAR(10),
StartDate DATE,
EndDate DATE
);
INSERT INTO #test1 VALUES
('Emp1', 'Band1', '2009-01-01', '2010-12-31'),
('Emp1', 'Band1', '2011-01-01', '2012-12-31'),
('Emp1', 'Band1', '2013-01-01', '2013-08-31'),
('Emp1', 'Band2', '2013-09-01', '2013-12-31'),
('Emp1', 'Band2', '2014-01-01', '2014-06-30'),
('Emp1', 'Band1', '2014-07-01', '2014-12-31'),
('Emp1', 'Band1', '2015-01-01', '2018-08-31'),
('Emp2', 'Band1', '2012-01-01', '2014-12-31'),
('Emp2', 'Band1', '2015-01-01', '2018-03-31');
WITH cte1 AS (
SELECT *,
CASE WHEN LAG(Band) OVER (PARTITION BY Employee ORDER BY StartDate) = Band /* AND DATEDIFF(...) */ THEN 0 ELSE 1 END AS Chg
FROM #test1
), cte2 AS (
SELECT *,
SUM(Chg) OVER (PARTITION BY Employee ORDER BY StartDate) AS Grp
FROM cte1
)
SELECT Employee, Band, MIN(StartDate), Max(EndDate)
FROM cte2
GROUP BY Employee, Band, Grp
DB Fiddle
This is the intermediate result in case you want to see how it works:
| Employee | Band | StartDate | EndDate | Chg | Grp |
|----------|-------|---------------------|---------------------|-----|-----|
| Emp1 | Band1 | 01/01/2009 00:00:00 | 31/12/2010 00:00:00 | 1 | 1 |
| Emp1 | Band1 | 01/01/2011 00:00:00 | 31/12/2012 00:00:00 | 0 | 1 |
| Emp1 | Band1 | 01/01/2013 00:00:00 | 31/08/2013 00:00:00 | 0 | 1 |
| Emp1 | Band2 | 01/09/2013 00:00:00 | 31/12/2013 00:00:00 | 1 | 2 |
| Emp1 | Band2 | 01/01/2014 00:00:00 | 30/06/2014 00:00:00 | 0 | 2 |
| Emp1 | Band1 | 01/07/2014 00:00:00 | 31/12/2014 00:00:00 | 1 | 3 |
| Emp1 | Band1 | 01/01/2015 00:00:00 | 31/08/2018 00:00:00 | 0 | 3 |
| Emp2 | Band1 | 01/01/2012 00:00:00 | 31/12/2014 00:00:00 | 1 | 1 |
| Emp2 | Band1 | 01/01/2015 00:00:00 | 31/03/2018 00:00:00 | 0 | 1 |
This is commonly known as Gaps and Islands.
One approach
Example
Declare #YourTable Table ([Employee] varchar(50),[Band] varchar(50),[Start] date,[End] date)
Insert Into #YourTable Values
('Emp1','Band1','2009-01-01','2010-12-31')
,('Emp1','Band1','2011-01-01','2012-12-31')
,('Emp1','Band1','2013-01-01','2013-08-31')
,('Emp1','Band2','2013-09-01','2013-12-31')
,('Emp1','Band2','2014-01-01','2014-06-30')
,('Emp1','Band1','2014-07-01','2014-12-31')
,('Emp1','Band1','2015-01-01','2018-08-31')
,('Emp2','Band3','2012-01-01','2014-12-31')
,('Emp2','Band3','2015-01-01','2018-03-31')
;with cte as (
Select *,Grp = sum(Flg) over (Partition By Employee Order by [End])
From (
Select *,Flg = IsNull(datediff(DAY,Lag([End],1) over (Partition By Employee,Band Order by [End]) ,[Start]) - 1,1)
From #YourTable
) A
)
Select Employee
,Band
,[Start] = min([Start])
,[End] = max([End])
From cte
Group By Employee,Band,Grp
Order by Employee,max([End])
Returns
Employee Band Start End
Emp1 Band1 2009-01-01 2013-08-31
Emp1 Band2 2013-09-01 2014-06-30
Emp1 Band1 2014-07-01 2018-08-31
Emp2 Band3 2012-01-01 2018-03-31
If it helps with the visualization, the CTE produces the following
Notice the Flag and Group Columns

How to sum values in column, grouped by date in SQL Server

I have the following:
Name |Dur |DateTime
Bill |10 |8/12/2018 07:00:00
Sue |4 |8/10/2018 09:00:00
Joe |23 |8/13/2018 07:15:00
Bill |13 |8/13/2018 09:15:00
Sue |4 |8/10/2018 19:00:00
Sue |23 |8/13/2018 07:25:00
Bill |10 |8/12/2018 15:18:00
Sue |4 |8/11/2018 13:00:00
Joe |23 |8/14/2018 07:15:00
I want to end up with:
Name |Tot|Date
Bill |20 |8/12/2018
Bill |13 |8/13/2018
Sue | 8 |8/10/2018
Sue | 4 |8/11/2018
Joe |23 |8/13/2018
Joe |23 |8/14/2018
So basically, sum the Dur each day, for each Name.
I tried:
SELECT
Name,
SUM([Dur]) AS Tot,
(CONVERT(VARCHAR, [DateTime], 101)) AS sDateTime
FROM
DailyTransactions
GROUP BY
DATEADD(day, DATEDIFF(day, 0, DateTime), 0), Name
You were close... just group by the same logic you used on your column conversion.
SELECT
Name,
SUM([Dur]) AS Tot,
(CONVERT(VARCHAR, [DateTime], 101))AS sDateTime
FROM
DailyTransactions
GROUP BY
(CONVERT(VARCHAR, [DateTime], 101))
This should do your work
SELECT
Name,
SUM([Dur]) AS Tot,
cast(DateTime as Date) AS Date
FROM
DailyTransactions
GROUP BY
cast(DateTime as Date), Name

Recursive first day of each month for current getdate

Using T-SQL, I want a new column that will show me the first day of each month, for the current year of getdate().
After that I need to count the rows on this specific date. Should I do it with CTE or a temp table?
If 2012+, you can use DateFromParts()
To Get a List of Dates
Select D = DateFromParts(Year(GetDate()),N,1)
From (values (1),(2),(3),(4),(5),(6),(7),(8),(9),(10),(11),(12)) N(N)
Returns
D
2017-01-01
2017-02-01
2017-03-01
2017-04-01
2017-05-01
2017-06-01
2017-07-01
2017-08-01
2017-09-01
2017-10-01
2017-11-01
2017-12-01
Edit For Trans Count
To get Transactions (assuming by month). It becomes a small matter of a left join to created Dates
-- This is Just a Sample Table Variable for Demonstration.
-- Remove this and Use your actual Transaction Table
--------------------------------------------------------------
Declare #Transactions table (TransDate date,MoreFields int)
Insert Into #Transactions values
('2017-02-18',6)
,('2017-02-19',9)
,('2017-03-05',5)
Select TransMonth = A.MthBeg
,TransCount = count(B.TransDate)
From (
Select MthBeg = DateFromParts(Year(GetDate()),N,1)
,MthEnd = EOMonth(DateFromParts(Year(GetDate()),N,1))
From (values (1),(2),(3),(4),(5),(6),(7),(8),(9),(10),(11),(12)) N(N)
) A
Left Join #Transactions B on TransDate between MthBeg and MthEnd
Group By A.MthBeg
Returns
TransMonth TransCount
2017-01-01 0
2017-02-01 2
2017-03-01 1
2017-04-01 0
2017-05-01 0
2017-06-01 0
2017-07-01 0
2017-08-01 0
2017-09-01 0
2017-10-01 0
2017-11-01 0
2017-12-01 0
For an adhoc table of months for a given year:
declare #year date = dateadd(year,datediff(year,0,getdate() ),0)
;with Months as (
select
MonthStart=dateadd(month,n,#year)
from (values(0),(1),(2),(3),(4),(5),(6),(7),(8),(9),(10),(11)) t(n)
)
select MonthStart
from Months
rextester demo: http://rextester.com/POKPM51023
returns:
+------------+
| MonthStart |
+------------+
| 2017-01-01 |
| 2017-02-01 |
| 2017-03-01 |
| 2017-04-01 |
| 2017-05-01 |
| 2017-06-01 |
| 2017-07-01 |
| 2017-08-01 |
| 2017-09-01 |
| 2017-10-01 |
| 2017-11-01 |
| 2017-12-01 |
+------------+
The first part: dateadd(year,datediff(year,0,getdate() ),0) adds the number of years since 1900-01-01 to the date 1900-01-01. So it will return the first date of the year. You can also swap year for other levels of truncation: year, quarter, month, day, hour, minute, second, et cetera.
The second part uses a common table expression and the table value constructor (values (...),(...)) to source numbers 0-11, which are added as months to the start of the year.
Not sure why you require recursive... But for first day of month you can try query like below:
Select Dateadd(day,1,eomonth(Dateadd(month, -1,getdate())))
declare #year date = dateadd(year,datediff(year,0,getdate() ),0)
;WITH months(MonthNumber) AS
(
SELECT 0
UNION ALL
SELECT MonthNumber+1
FROM months
WHERE MonthNumber < 11
)
select dateadd(month,MonthNumber,#year)
from months

How to get rows per day (Fill gaps when no records)

I have the following results
Date | EmployeeID
2015-11-18 | 1
2015-11-18 | 1
2015-11-18 | 1
2015-11-19 | 1
2015-11-19 | 1
2015-11-20 | 1
2015-11-20 | 1
2015-11-20 | 1
2015-11-25 | 1
But given a range of dates (2015-11-15 - 2015-11-30) I want to display something like this
Date | NbEmployees
2015-11-15 | 0
2015-11-16 | 0
2015-11-17 | 0
2015-11-18 | 3
2015-11-19 | 2
2015-11-20 | 3
2015-11-21 | 0
2015-11-22 | 0
2015-11-23 | 0
2015-11-24 | 0
2015-11-25 | 1
2015-11-26 | 0
2015-11-27 | 0
2015-11-28 | 0
2015-11-29 | 0
2015-11-30 | 0
I've using this approach by I only get the values from the table with data
DECLARE #StartDate DATE = '2015-11-15 00:00:00', #EndDate DATE = '2015-11-30 23:59:00'
DECLARE #CurrentDate DATE = #StartDate
DECLARE #DateRange TABLE (CurrentDate DATETIME)
WHILE(#CurrentDate <= #EndDate)
BEGIN
INSERT INTO #DateRange VALUES(#CurrentDate)
SET #CurrentDate = DATEADD(DAY, 1, #CurrentDate)
END
SELECT r.CurrentDate, COUNT(EmployeeID)
FROM Employee e
RIGHT JOIN #DateRange r ON e.HireDate = r.Date
Results:
Date | NbEmployees
2015-11-18 | 3
2015-11-19 | 2
2015-11-20 | 3
2015-11-25 | 1
Try it like this
DECLARE #tbl TABLE([Date] DATE, EmployeeID INT);
INSERT INTO #tbl VALUES
('2015-11-18',1)
,('2015-11-18',1)
,('2015-11-18',1)
,('2015-11-19',1)
,('2015-11-19',1)
,('2015-11-20',1)
,('2015-11-20',1)
,('2015-11-20',1)
,('2015-11-25',1);
DECLARE #StartDate DATE = '2015-11-15 00:00:00', #EndDate DATE = '2015-11-30 23:59:00'
DECLARE #CurrentDate DATE = #StartDate
DECLARE #DateRange TABLE (CurrentDate DATETIME)
WHILE(#CurrentDate <= #EndDate)
BEGIN
INSERT INTO #DateRange VALUES(#CurrentDate)
SET #CurrentDate = DATEADD(DAY, 1, #CurrentDate)
END
SELECT CurrentDate,ISNULL(NbEmployees,0) AS NbEmployees
FROM #DateRange
LEFT JOIN
(
SELECT COUNT(tbl.EmployeeID) AS NbEmployees
,tbl.[Date] AS Date
FROM #tbl AS tbl
GROUP BY tbl.[Date]
) AS grouped ON CurrentDate=grouped.[Date]
The result
2015-11-15 00:00:00.000 0
2015-11-16 00:00:00.000 0
2015-11-17 00:00:00.000 0
2015-11-18 00:00:00.000 3
2015-11-19 00:00:00.000 2
2015-11-20 00:00:00.000 3
2015-11-21 00:00:00.000 0
2015-11-22 00:00:00.000 0
2015-11-23 00:00:00.000 0
2015-11-24 00:00:00.000 0
2015-11-25 00:00:00.000 1
2015-11-26 00:00:00.000 0
2015-11-27 00:00:00.000 0
2015-11-28 00:00:00.000 0
2015-11-29 00:00:00.000 0
2015-11-30 00:00:00.000 0
With something like this you could create your date-tally on the fly (avoid loops!!!)
DECLARE #StartDate DATE = '2015-11-15 00:00:00', #EndDate DATE = '2015-11-30 23:59:00';
WITH DayCount(Nmbr) AS
(
SELECT TOP (DATEDIFF(DAY,#StartDate,#EndDate)+1) ROW_NUMBER() OVER(ORDER BY (SELECT NULL))-1 FROM sys.objects
)
,RunningDates(CurrentDate) AS
(
SELECT DATEADD(DAY,Nmbr,#StartDate) FROM DayCount
)
SELECT * FROM RunningDates
This is bound to the max count of sys.objects... You'll find a lot of examples how to create running numbers on the fly or how to create a date-tally table (for example this: https://stackoverflow.com/a/32474751/5089204)
You don't need to create and maintain a list_of_dates table. You could just outter join to something like this:
For SqlServer:
SELECT
DATEADD(DAY,number,'20010101') [Date]
FROM
master..spt_values
WHERE
type = 'P'
AND DATEADD(DAY,number,'20010101') <= '20010104'
Or for Oracle, this:
select
rownum - 1 + to_date('01-JAN-2001', 'dd-mon-yyyy') dates
from
all_objects
where
rownum < to_date('01-FEB-2001', 'dd-mon-yyyy') - to_date('01-JAN-2001', 'dd-mon-yyyy') + 2
The output from this query looks like this:
DATES
---------
01-JAN-01
02-JAN-01
03-JAN-01
04-JAN-01
05-JAN-01
06-JAN-01
07-JAN-01
08-JAN-01
09-JAN-01
10-JAN-01
11-JAN-01
12-JAN-01
13-JAN-01
14-JAN-01
15-JAN-01
16-JAN-01
17-JAN-01
18-JAN-01
19-JAN-01
20-JAN-01
21-JAN-01
22-JAN-01
23-JAN-01
24-JAN-01
25-JAN-01
26-JAN-01
27-JAN-01
28-JAN-01
29-JAN-01
30-JAN-01
31-JAN-01
01-FEB-01

Stored Procedure - Start and end date, looking at today's date

I have a table with this entries:
StartDate | EndDate
2016-01-06 | 2016-01-16
2016-01-06 | 2016-01-16
2016-01-06 | 2016-01-16
2016-01-06 | 2016-01-16
2016-01-06 | 2016-01-16
2016-01-06 | 2016-01-16
2016-01-06 | 2016-01-16
2016-01-06 | 2016-01-16
2016-01-06 | 2016-01-16
2016-01-06 | 2016-01-16
2016-01-06 | 2016-01-16
2016-01-06 | 2016-01-16
2016-01-06 | 2016-01-16
2016-01-06 | 2016-01-16
2016-01-07 | 2016-01-17
2016-01-07 | 2016-01-17
2016-01-07 | 2016-01-17
2016-01-07 | 2016-01-17
2016-01-07 | 2016-01-17
2016-01-07 | 2016-01-17
2016-01-07 | 2016-01-17
2016-01-07 | 2016-01-17
2016-01-08 | 2016-01-18
2016-01-08 | 2016-01-18
2017-01-01 | 2017-01-10
2026-01-06 | 2026-01-16
2026-01-07 | 2026-01-17
And my query in stored procedure is:
SELECT ROW_NUMBER() OVER ( ORDER BY [StartDate] ASC) as ROWNUM, [Oid]
From [dbo].[Ument]
Where (
(#StartDate is null or StartDate >= #StartDate)
or (#EndDate is null or EndDate <= #EndDate)
)
I want to search by #StartDate written by user or, if is null/empty, by #StartDate >= today's date.
But, at the same time, I want to search by #endDate, written by user or, if is null/empty, EndDate >= today's.
If today's is between two dates, i need to return it.
Like this:
#startDate isn't null?
YES: use the #startDate written by user to filter startDate >= #StartDate.
NO: use today's date to put startDate >= today.
#endDate isn't null?
YES: use the #endDate written by user to filter endDate <= #endDate
NO: use max-date (e.g.: 2050/12/31) to filter endDate <= max-Date
Is this what you want?
WHERE startDate >= COALESCE(#StartDate, GETDATE()) AND
endDate <= COALESCE(#EndDate, GETDATE())
You may want this logic, but with the current date with no time:
WHERE startDate >= COALESCE(#StartDate, CAST(GETDATE() AS DATE)) AND
endDate <= COALESCE(#EndDate, CAST(GETDATE() AS DATE))
After the comment, diabolickman's question and Gordon's answer can be mixed like:
SELECT ROW_NUMBER() OVER ( ORDER BY [StartDate] ASC) as ROWNUM, [Oid]
From [dbo].[Ument]
Where (
StartDate >= ISNULL(#StartDate, CAST(GETDATE() AS DATE))
AND (#EndDate is null or EndDate <= #EndDate)
)
This way, End date is ignored if it's null, so you dont need to compare it against max date.
Changed middle OR to AND, assuming user wants to filter a date range.
I used ISNULL instead of COALESCE, just to show another alternative.
I think my problem is solved! :)
I change the last solution to this and the query returns what I want!
SELECT ROW_NUMBER() OVER ( ORDER BY [StartDate] ASC) as ROWNUM, [Oid] From [dbo].[Ument]
Where (
StartDate >= ISNULL(#StartDate, CAST(GETDATE() AS DATE))
and EndDate <= ISNULL(#EndDate, CAST('20501231' AS DATE))
)
Thanks for the help ramazan's and Gordon's. :)

Resources