GETDATE()-n when compared to datetime2(7) excludes the matching value - sql-server

I have a situation where querying a datetime2(7) field with GETDATE()-n is not returning expected output.
Query with >= GEDATE()-20 returns all dates excluding 4/27 (if run today 5/17)
Query with >= 4/27/2018 returns all dates including 4/27.
Is it something to do with the timepart? even if the timepart is all 0's?
DECLARE #MinDate DATE = '04-01-2018',
#MaxDate DATE = '05-17-2018';
SELECT TOP (DATEDIFF(DAY, #MinDate, #MaxDate) + 1)
DateCol = CAST(DATEADD(DAY, ROW_NUMBER() OVER(ORDER BY a.object_id) - 1, #MinDate) AS DATETIME2(7))
INTO #temp
FROM sys.all_objects a
CROSS JOIN sys.all_objects b;
--SELECT * FROM #temp
SELECT COUNT(*) FROM #temp WHERE DateCol >= GETDATE()-20
SELECT COUNT(*) FROM #temp WHERE DateCol >= '2018-04-27' --excludes the date 4/27
/*
SELECT * FROM #temp WHERE DateCol >= GETDATE()-20 --Excludes 4/27
SELECT * FROM #temp WHERE DateCol >= '2018-04-27' --Expected output includes 4/27
*/
DROP TABLE #temp

This is due to '2018-04-27 00:00:00.0000000' not greater than GETDATE()-20.
GETDATE()-20 will give something like '2018-04-27 10:25:37.680'
For one case you are using only date and for the other scenario it is date and time.
You should change your query like following to change the date-time to date before comparing to get the desired output.
SELECT COUNT(*) FROM #temp WHERE DateCol >= cast(GETDATE() -20 as date)

Related

Get data from the last day of the month without the use of loops or variables

I wrote a query that should select the last record of each month in a year. I'd like to create a View based on this select, that I could run later in my project, but unfortunately I can't use any while loops or variables in a view command. Is there a way to select all these records - last days of a month in a View that I can use later?
My desired effect of the view:
The query that I'm trying to implement in a view:
DECLARE #var_day01 DATETIME;
DECLARE #month int;
SET #month = 1;
DROP TABLE IF EXISTS #TempTable2;
CREATE TABLE #TempTable2 (ID int, date datetime, INP2D float, INP3D float, ID_device varchar(max));
WHILE #month < 13
BEGIN
SELECT #var_day01 = CONVERT(nvarchar, date) FROM (SELECT TOP 1 * FROM data
WHERE DATEPART(MINUTE, CONVERT(nvarchar, date)) = '59'
AND
MONTH(CONVERT(nvarchar, date)) = (CONVERT(nvarchar, #month))
ORDER BY date DESC
) results
ORDER BY date DESC;
INSERT INTO #TempTable2 (ID, date, INP2D,INP3D,ID_device)
SELECT * FROM data
WHERE DATEPART(MINUTE, CONVERT(nvarchar, date)) = '59'
AND
MONTH(CONVERT(nvarchar, date)) = (CONVERT(nvarchar, #month))
AND
DAY(CONVERT(nvarchar, date)) = CONVERT(datetime, DATEPART(DAY, #var_day01))
ORDER BY date DESC
PRINT #var_day01
SET #month = #month +1;
END
SELECT * FROM #TempTable2;
If you are actually just after the single most recent row for each month, there is no need for a while loop to achieve this. You just need to identify the max date value for each month and then filter your source data for those for those rows.
One way to achieve this is via a row_number window function:
declare #t table(id int,dt datetime2);
insert into #t values(1,getdate()-40),(2,getdate()-35),(3,getdate()-25),(4,getdate()-10),(5,getdate());
select id
,id_device
,dt
from(select id
,id_device
,dt
,row_number() over (partition by id_device, year(dt), month(dt) order by dt desc) as rn
from #t
) as d
where rn = 1;
You can add a simple where to your select statement, in where clause you will add one day to the date field and then select the day from the resultant date. If the result date is 1 then only you will select that record
the where clause for your query will be : Where Day(DATEADD(d,1,[date])) = 1

Creating a monthly report in T-SQL

I have a table with the following columns
CaseID
DateLogged
CompletionDate
I am trying to create a monthly stock report.
I need to identify monthly which cases are New, current and Completed each month
for instance, All cases logged only in August are new cases while all cases completed in august would show completed and all cases logged that are not completed will be current.
DROP TABLE IF EXISTS #temptable
-- Create date variables
SET dateformat ymd
DECLARE #datefrom datetime = CONVERT(DATETIME, '2019-04-01 00:00:00', 121)
DECLARE #dateto datetime = (SELECT CAST(DATEADD(DAY, -DAY(GETDATE()), GETDATE()) AS date))
-- Recursive date table creation
;WITH monthserial AS
(
SELECT #datefrom AS monthdate
UNION ALL
SELET DATEADD(MONTH, 1, monthdate)
FROM monthserial
WHERE monthdate < #dateto
)
SELECT MN.*
INTO #temptable
FROM monthserial MN
SELECT * FROM MainTable VW
CROSS JOIN #temptable TBL
WHERE DateLogged <= monthdate) test
You will need to use case-when for your situation:
select CaseID,
case
when not (CompletionDate is null) then 'Completed'
when DateLogged >= #input then 'New'
else 'Current'
end
from yourtable
order by DateLogged;
EDIT
Since we are interested about the last entry, we can add a where clause, like this:
select CaseID,
case
when not (CompletionDate is null) then 'Completed'
when DateLogged >= #input then 'New'
else 'Current'
end
from yourtable
where not exists (
select 1
from yourtable inner
where inner.CaseID = yourtable.CaseID and inner.CompletionDate < yourtable.CompletionDate
)
order by DateLogged;

Get dates between 2 dates with equal intervals

I have 2 dates 01/04/2017 and 30/04/2017. I want all the dates between these 2 dates with 7 days interval.
Expected Output :
01/04/2017
08/04/2017
15/04/2017
22/04/2017
29/04/2017
Please help!!
DECLARE #StartDate DATETIME,
#EndDate DATETIME
SELECT #StartDate = '2017-04-01',
#EndDate = '2017-04-30'
SELECT DATEADD(DAY, number*7, #StartDate)
FROM master.dbo.spt_values
WHERE type='P'
AND #EndDate >= DATEADD(DAY, number*7, #StartDate)
One method would be to use a Calendar table. Then return the results from there using the modulus to get the 7th rows:
WITH Dates AS(
SELECT *,
ROW_NUMBER() OVER (ORDER BY [date]) AS RN
FROM DateTable
WHERE [Date] BETWEEN '20170401' AND '20170430')
SELECT *
FROM Dates
WHERE (RN - 1) % 7 = 0;
I've used this solution, as from your post you imply that you might supply any date range, and that the 1st day may not necessarily be a Monday (or other specific day).
Try this
DECLARE #STRT DATETIME='04/01/2017',#END DATETIME ='04/30/2017'
;WITH CTE
AS
(
SELECT
MyDate = CAST(#STRT AS DATETIME)
UNION ALL
SELECT
MyDate = CAST(MyDate AS DATETIME)+7
FROM CTE
WHERE CAST(MyDate AS DATETIME)+7 < CAST(#END AS DATETIME)
)
SELECT
*
FROM CTE
result
Declare #StartDate DATE=CONVERT(DATE,'01/04/2017',104),#EndDate DATE=CONVERT(DATE,'01/12/2017',104)
Declare #String NVARCHAR(MAX)=''
WHILE (#StartDate<=#EndDate AND DATEDIFF(wk,#StartDate,#EndDate)>=0)
BEGIN
SET #String=#String+CONVERT(NVARCHAR(100),#StartDate)+CHAR(10)+CHAR(13)
SET #StartDate=DATEADD(d,7,#StartDate)
END
PRINT #String
GO

Sequence of dates starting since 2015-01-01 until today

I want to produce sequence of dates since given date until today using one select command. It is possible?
WITH DATES_CTE AS (
SELECT TOP 100000
ROW_NUMBER() OVER (ORDER BY a.object_id) - 1 AS DayNumber
FROM
sys.all_columns a
CROSS JOIN
sys.all_columns b)
SELECT
DATEADD(DAY, DayNumber, 0) AS DateValue
FROM
DATES_CTE
WHERE
DATEADD(DAY, DayNumber, 0) >= '2016-01-01'
AND DATEADD(DAY, DayNumber, 0) < '2016-05-01';
Try this with CTE.
WITH CTE_DATE
AS
( SELECT CONVERT(DATE,'2015-01-01') AS CDATE
UNION ALL
SELECT DATEADD(DAY,1,CDATE)
FROM CTE_DATE
WHERE DATEADD(DAY,1,CDATE) <= GETDATE()
)
SELECT * FROM CTE_DATE
option (maxrecursion 0) -- for unlimited recursion
You can use the option option (maxrecursion 0) to avoid the limit recursion.
CREATE TABLE #date (datevalues date)
DECLARE #mindate DATE = '2015-01-01',
#maxdate DATE = GETDATE()
WHILE #mindate <= #maxdate
BEGIN
INSERT INTO
#date (datevalues)
SELECT #mindate
SELECT #mindate = dateadd(dd,1,#mindate)
END
GO
SELECT *FROM #date
GO
DROP TABLE #date
GO

Searching date between two given Dates

I have two specific dates.
lets say from 2014-04-04 To 2015-10-04.
I have a plan that says classes of Blah course will be on mon, wed and Fri.
Now I want to get the dates of each mon, wed and Fri from 2014-04-04 to 2015-10-04.
With a calendar table it is simple:
SELECT t.*
FROM dbo.TableName t
INNER JOIN CalendarTable c
ON t.DateColumn = c.Date
WHERE c.Date between '2014-04-04' AND '2015-10-04'
AND DATEPART(dw, c.Date) IN (1,3,5)
How to generate a calendar table (look for "Calendar table").
The standard reply to this by any seasoned SQL Server veteran, would be to create a calendar table. But all too often this is scoffed. So here's a slow and out-of-the-box method:
DECLARE #startDate DATE = '2014-04-04', #endDate DATE = '2015-10-04';
WITH CTE(N) AS (SELECT 1 FROM (VALUES(1),(1),(1),(1),(1),(1),(1),(1),(1),(1))a(N)),
CTE2(N) AS (SELECT 1 FROM CTE x CROSS JOIN CTE y),
CTE3(N) AS (SELECT 1 FROM CTE2 x CROSS JOIN CTE2 y),
CTE4(N) AS (SELECT 1 FROM CTE3 x CROSS JOIN CTE3 y),
CTE5(N) AS (SELECT 1 FROM CTE4 x CROSS JOIN CTE4 y),
CTE6(N) AS (SELECT 0 UNION ALL
SELECT TOP (DATEDIFF(day,#startDate,#endDate))
ROW_NUMBER() OVER(ORDER BY (SELECT NULL))
FROM CTE5),
TALLY(N) AS (SELECT DATEADD(day, N, #startDate)
FROM CTE6
WHERE DATENAME(weekday,DATEADD(day, N, #startDate)) IN ('Monday','Tuesday','Wednesday'))
SELECT N
FROM TALLY
ORDER BY N;
You can use a Recursive CTE if you do not have numbers table. Something like this. Note that the DATEPART(weekday,Dates) IN(1,3,5) is based on your setting of SELECT ##DATEFIRST.
For example If ##DATEFIRST is 1 then use DATEPART(weekday,Dates) IN(1,3,5)
DECLARE #StartDate DATETIME
DECLARE #EndDate DATETIME
SET #StartDate = '2014-04-04'
SET #EndDate = '2015-10-04'
;WITH CTE AS
(
SELECT #StartDate Dates
UNION ALL SELECT DATEADD(d,1,Dates) FROM CTE WHERE DATEADD(d,1,Dates) <=#EndDate
)
SELECT Dates,DATENAME(weekday,Dates) FROM CTE
WHERE DATEPART(weekday,Dates) IN(1,3,5)
OPTION (MAXRECURSION 0);
GO
DECLARE #StartDate DATETIME
DECLARE #EndDate DATETIME
SET #StartDate = '2014-04-04'
SET #EndDate = '2015-10-04'
;WITH CTE AS
(
SELECT #StartDate Dates
UNION ALL SELECT DATEADD(d,1,Dates) FROM CTE WHERE DATEADD(d,1,Dates) <=#EndDate
)
SELECT Dates,DATENAME(weekday,Dates) FROM CTE
WHERE DATEPART(weekday,Dates) IN(1,3,5)
OPTION (MAXRECURSION 0);
GO
--- thanks to #ughai
I've comeup with another way to do this.
this query will not only Show the dates in between but also it will compare the dates u want to compare with.
Q.Dates Comparison
DECLARE #StartDate DATETIME
DECLARE #EndDate DATETIME
SET #StartDate = '2014-12-22'
SET #EndDate = '2015-02-13'
drop table #TabCourseDetailID
SELECT ROW_NUMBER() OVER(ORDER BY CourseDetailID asc) AS Row,
CourseDetailID
into #TabCourseDetailID
from coursedetail
where UnitType='T' and courseID =1
Declare #counter as int
Declare #CourseDetailID varchar(500)
set #counter = 0
Declare #TempTable Table (FirstValue datetime,LastValue int)
while #StartDate <= #EndDate
begin
If DATEPART(WeekDay,#StartDate) IN (2,4,6)
begin
Set #Counter = #counter+1
Select #CoursedetailId=CoursedetailId
from #TabCourseDetailID
where row=#counter
insert into #TempTable (FirstValue,LastValue)
values (#StartDate,#CoursedetailId)
end
set #StartDate =DATEADD(d,1,#StartDate)
end
select t.LastValue,
t.FirstValue,
bp.conductedDate
from batchprogress bp
Join #TempTable t on (t.LastValue=bp.CoursedetailID)
where CourseID =1 and batchID =5
order by t.lastvalue

Resources