Working with timestamps in sql - sql

I have an if statement in a stored procedure that is being used to derive some time value. It looks like this:
DECLARE #foo TIME
IF (SELECT CONVERT(TIME,SYSUTCDATETIME())) > '15:00'
SET #foo = DATEADD(hh,-15,CONVERT(TIME,SYSUTCDATETIME()))
ELSE
SET #foo = DATEADD(hh,+9,CONVERT(TIME,SYSUTCDATETIME()))
later on i would like to use that value in the following WHERE clause:
AND created_at > DATEADD(hh,-#DailyLimitOffsetTime, CONVERT(TIME,SYSUTCDATETIME()))
I keep on getting an error that the data type time is invalid for the minus operator. How can i get around this to make the and clause work. I have tried converting the data type and i somewhat understand the issue DATEADD(hh) is looking for param 2 to be an int not a time. Is there some easier way to do this, I must admit if you couldn't tell already I am not good with timestamps at all. Any help is appreciated.
DECLARE #DailyLimitOffsetTime TIME
IF (SELECT CONVERT(TIME,SYSUTCDATETIME())) > '15:00'
SET #DailyLimitOffsetTime = DATEADD(hh,-15,CONVERT(TIME,SYSUTCDATETIME()))
ELSE
SET #DailyLimitOffsetTime = DATEADD(hh,+9,CONVERT(TIME,SYSUTCDATETIME()))
IF #Limit <=
(
SELECT COUNT(*)
FROM dbo.fooTable
WHERE offerId = #OfferID
AND created_at >
DATEADD(hh,DATEPART(hh,-#DailyLimitOffsetTime),CONVERT(TIME,SYSUTCDATETIME()))
)
SET #ErrorTypeID = 9400
I am sure there is a much better way to do this, and if so please share how. As always any help is appreciated. If you need any further explanation on the issue let me know. Its a bit messy this one.

Second argument in DATEADD function has to be resolved to an int
AND created_at > DATEADD(hh, -DATEPART(hh, #DailyLimitOffsetTime), CONVERT(TIME,SYSUTCDATETIME()))
OR
DECLARE #time time = CONVERT(TIME, SYSUTCDATETIME())
IF #Limit <=
(
SELECT COUNT(*)
FROM dbo.fooTable
WHERE offerId = #OfferID
AND created_at >
CASE WHEN #time > '15:00'
THEN DATEADD(hh, 15, DATEADD(hh, -DATEPART(hh, #time), #time))
ELSE DATEADD(hh, 09, DATEADD(hh, -DATEPART(hh, #time), #time)) END
END
)
SET #ErrorTypeID = 9400

I don't get what you are doing as you will always make the same time and not account for the date just the time. You don't want that if you are trying to show a different day forward when the UTC time is after 3 PM at a location. So if you want to go nine hours ahead you won't because you are only accounting for the current day by using the time frame. So if it was 8 PM of 1-16-12 you would set the time to be 5 AM. I think you need to set the DATETIME for what you want, not just the time.
DECLARE #foo Datetime
IF (SELECT CONVERT(TIME,SYSUTCDATETIME())) > '15:00'
SET #foo = Dateadd(hh, datediff(hh, 0, sysutcdatetime()) -15, 0)
ELSE
SET #foo = Dateadd(hh, datediff(hh, 0, sysutcdatetime()) + 9, 0)
select #foo

Related

Multiple DATEADD functions in one query - TSQL

I'm trying to make multiple edits on a random date to leave a full random datetime within a range of dates (3 months back, 3 months forward) but setting the Hours/Minutes/Seconds/Milliseconds to 0.
I'm doing this so I can then add a random amount of time to create activity start and end times that will always fit within office working hours. The script below sets a variable for the start time of the activity, then carries out 5 separate edits to this variable to zero the time element.
Is there an easier way to carry out multiple DATEADD edits, it seems clunky!
DECLARE #STARTTIME DATETIME
DECLARE #ENDTIME DATETIME
SET #STARTTIME = (SELECT DATEADD(DAY,ABS(CHECKSUM(NEWID()) % 180), (select dateadd(dd, -90, getdate()) )))
SET #STARTTIME = (SELECT DATEADD(HH, - (SELECT DATEPART(HH,#STARTTIME)),#STARTTIME))
SET #STARTTIME = (SELECT DATEADD(MI, - (SELECT DATEPART(MI,#STARTTIME)),#STARTTIME))
SET #STARTTIME = (SELECT DATEADD(SS, - (SELECT DATEPART(SS,#STARTTIME)),#STARTTIME))
SET #STARTTIME = (SELECT DATEADD(MS, - (SELECT DATEPART(MS,#STARTTIME)),#STARTTIME))
SET #STARTTIME = (SELECT DATEADD(hh,(SELECT FLOOR(RAND()*(15-08)+08)), #STARTTIME))
SET #ENDTIME = (SELECT DATEADD(hh,(SELECT FLOOR(RAND()*(3-1)+1)), #STARTTIME))
SELECT
#STARTTIME AS 'STARTTIME',
#ENDTIME AS 'ENDTIME'
Results
STARTIME 2017-04-02 13:00:00.000
ENDTIME 2017-04-02 15:00:00.000
There is not a need to use newid() in T-SQL code. It is only needed within a query to generate multiple random numbers.
So:
set #starttime = cast(datedd(day, floor(rand() * 180 - 90), getdate()) as date);
set #starttime = dateadd(hour, floor(rand()*(15-08)+08), #starttime);
set #enddtime = dateadd(hour, floor(rand()*(3-1)+1), #starttime);
Notes:
This uses cast(. . . as date) to remove the time component of the date.
There is no need to have nested select statements.
For T-SQL code, you can use rand(), rather than the newid() work-around (that is needed within a single query to generate multiple random values).
Don't use date part abbreviations such as "hh". Just spell out the date part. The code is much easier to write and maintain.
You convert it to a Date data type would set the time part to 00:00:000
DECLARE #STARTTIME DATETIME
DECLARE #ENDTIME DATETIME
SET #STARTTIME = cast((SELECT DATEADD(DAY,ABS(CHECKSUM(NEWID()) % 180), (select dateadd(dd, -90, getdate()) ))) as date)
SET #STARTTIME = (SELECT DATEADD(hh,(SELECT FLOOR(RAND()*(15-08)+08)), #STARTTIME))
SET #ENDTIME = (SELECT DATEADD(hh,(SELECT FLOOR(RAND()*(3-1)+1)), #STARTTIME))
SELECT
#STARTTIME AS 'STARTTIME',
#ENDTIME AS 'ENDTIME'

Query of set time range relative to current date

I come in to work 6.30am, and need to audit what happened from 5pm when I left to 6.30am this morning. I have used code to search 13.5 hours back from any given time:
SELECT * FROM TRANSACTION_HISTORY
WHERE TRANSACTION_HISTORY.ACTIVITY_DATE_TIME > (SELECT DATEADD(hour,-13.5,(SELECT MAX (TRANSACTION_HISTORY.ACTIVITY_DATE_TIME) FROM TRANSACTION_HISTORY)))
Problem is if I run query later, I lose time from the start, eg. If I run query at 7am, I only get results from 5.30pm onwards. Rather than change criteria every day, I wanted to able to search from 6.30am of the current day, back to 5.30pm of the previous day. Can this be done?
Normally, I don't advise using between for datetime, because the boundary conditions can cause confusion. I don't think that is the case.
Here is one method:
SELECT *
FROM TRANSACTION_HISTORY th
WHERE th.ACTIVITY_DATE_TIME between cast(cast(getdate() -1 as date) as datetime) + 17.5/24.0
cast(cast(getdate() as date) as datetime) + 6.5/24.0;
The expression cast(cast(getdate() as date) as datetime) is truncating the datetime value to midnight. As a datetime, SQL Server lets you add a number which is understood as a fraction of a day. Hence, 17.5/24 represents "5:30". This addition doesn't work for the date data type.
You can do this.
DECLARE #dt datetime
DECLARE #dt1 datetime
DECLARE #dt2 datetime
SET #dt = CONVERT(datetime, CONVERT(VARCHAR(10), getdate(), 101 ), 101)
SET #dt1 = dateadd(mi, 30, dateadd(hh, 6, #dt))
SET #dt2 = dateadd(mi, -27*30, #dt1)
SELECT #dt1 as StartDate, #dt2 as EndDate
For additional details what this script does you may check these pages.
http://technet.microsoft.com/en-us/library/ms174450%28v=sql.105%29.aspx
http://technet.microsoft.com/en-us/library/ms186819%28v=sql.105%29.aspx

How to get date difference between two dates in same year with one date is from an input date not from the year

Well this is my case: I have an input date X (dd-mm-yyyy), and I want to count the number of days between it with the year part is changed into current year and today's date in SQL. I t comes with the following condition, after the year is changed temporarily: (Here's my current idea of the logic)
- If date X is earlier than today, then difference = datediff(X,now), with the X year is current year
- If date X is later than today, then difference = datediff(X,now), with the X year is one year before
Sample case:
1st case: The input date is 6-6-1990. Today (automatically generated) is 22-8-2011. Then the difference will be = datediff(6-6-2011,22-08-2011)
2nd case: The input date is 10-10-1990. Today (automatically generated) is 22-8-2011. Then the difference will be = datediff(10-10-2010,22-08-2011)
Any idea how to do this in SQL (in SQL Server)? Or is there any other more simple alternatives for this problem? I'd also like this to be done in the query and not using a stored procedure or function
Sorry if there's already a similar question, I just don't know the exact keyword for this problem :( if there's a question like this previously, feel free to direct me there.
Thanks in advance
Here is the implementation (if I understood the logic you need correctly):
USE YourDbName
GO
CREATE FUNCTION YearPartDiff (#date datetime)
RETURNS int
AS
BEGIN
DECLARE #dateCurrentYear datetime
SET #dateCurrentYear = DATEADD(year, YEAR(GETDATE()) - YEAR(#date), #date)
DECLARE #result int
IF #dateCurrentYear < GETDATE()
SET #result = ABS(DATEDIFF(day, #dateCurrentYear, GETDATE()))
ELSE
SET #result = ABS(DATEDIFF(day, DATEADD(year, -1, #dateCurrentYear), GETDATE()))
RETURN(#result)
END
GO
And the example of usage:
USE YourDbName
GO
DECLARE #someDate datetime
SET #someDate = '2011-06-06'
SELECT dbo.YearPartDiff(#someDate) /*returns 77*/
SET #someDate = '2010-10-10'
SELECT dbo.YearPartDiff(#someDate) /*returns 316*/
Basically, #Andrei's solution, but in a single statement:
SELECT
DayDiff = DATEDIFF(
DAY,
DATEADD(YEAR, CASE WHEN LastOcc > GETDATE() THEN -1 ELSE 0 END, LastOcc),
GETDATE()
)
FROM (
SELECT LastOcc = DATEADD(YEAR, YEAR(GETDATE()) - YEAR(#InputDate), #InputDate)
) s
This seems to do the job
SELECT DATEDIFF(DAY, CONVERT(DATETIME, N'2011-06-06'), CONVERT(DATETIME, N'2011-08-22'))
So the basic syntax is
SELECT DATEDIFF(DAY, CONVERT(DATETIME, N'yyyy-mm-dd'), CONVERT(DATETIME, N'yyyy-mm-dd '))
Alternatively, you can use GETDATE() instead of the string for today's date
I have used "SELECT DATEDIFF( D, "+myDate+", GETDATE())" in my code, on SQL Server 2005. It works for me. The value myDate of course would be the DateTime input value.
you should try this query:
create table #T (inp_date datetime)
insert #T values ('06-06-1990')
insert #T values ('08-22-1990')
insert #T values ('10-10-1990')
--select * from #T
select inp_date, GETDATE(),
CASE
WHEN DATEADD(yy,DATEDIFF(yy,inp_date,GETDATE()),inp_date) <= GETDATE()
THEN DATEDIFF(dd,DATEADD(yy,DATEDIFF(yy,inp_date,GETDATE()),inp_date),GETDATE())
ELSE DATEDIFF(dd,DATEADD(yy,DATEDIFF(yy,inp_date,GETDATE())-1,inp_date),GETDATE())
END
from #T

SQL Query based on a while loop

I am trying to construct an sql query using a while loop that increments a datetime by one minute each iteration and then generates a select statement based on the time:
declare #dt datetime
set #dt = '2011-7-21'
while #dt < '2011-7-22'
begin
select Count(*) From Actions Where Timestamp = #dt
set #dt = DATEADD(mi, 1, #dt)
end
The query works as intended except that every iteration of the while loop seems to produce a new query entirely, rather than simply a new row. Is there a way to construct this so that its one single query and each row is generated by the incrementation of the loop?
I believe this occurs because the select statement is inside the loop, but I'm not sure how to construct it a different way that works.
EDIT - Here is what I came up with using a temporary table, but it is slow. Maybe there is a faster way? If not thats fine, atleast this works:
create table #temp
(
[DT] datetime not null,
[Total] int not null
)
declare #dt datetime
declare #result int
set #dt = '2011-7-21'
while #dt < '2011-7-22'
begin
set #result = Count(*) From Actions Where Timestamp = #dt
insert #temp ([DT],[Total]) values (#dt, #result)
set #dt = DATEADD(mi, 1, #dt)
end
select * from #temp;
drop table #temp;
One way by using a table of numbers
declare #dt datetime
set #dt = '2011-07-21'
select DATEADD(mi, number, #dt)
from master..spt_values
where type = 'P'
and DATEADD(mi, number, #dt) < '2011-07-22'
If you have your own number table, use that
See here for more info http://wiki.lessthandot.com/index.php/Date_Ranges_Without_Loops
you full query would be like
DECLARE #dt DATETIME
SET #dt = '2011-07-21'
SELECT x.SomeTime,y.TheCount FROM
(SELECT DATEADD(mi, number, #dt) as SomeTime FROM master..spt_values
WHERE TYPE = 'P'
AND DATEADD(mi, number, #dt) < '2011-07-22') x
LEFT JOIN (
SELECT TIMESTAMP, COUNT(*) AS TheCount
FROM Actions
GROUP BY TIMESTAMP
) AS y
ON x.SomeTime = dateadd(mi, datediff(mi, 0, y.Timestamp)+0, 0)
If you have a numbers table (from 0 to a million or whatever), this is relatively simple:
SELECT *
FROM Numbers AS n
LEFT JOIN (
SELECT Timestamp, COUNT(*) AS Ct
FROM Actions
GROUP BY Timestamp
) AS ActionSummary
ON ActionSummary.Timestamp = DATEADD(mi, n.Number, '2011-07-21')
WHERE DATEADD(mi, n.Number, '2011-07-21') < '2011-07-22'
ORDER BY DATEADD(mi, n.Number, '2011-07-21')
No need for loops.
There's ways to optimize this, but that should be fairly understandable as it is.
Also note that the timestamps cannot have any seconds or fractions of a second for this to work (your original has this problem as well).

Get specific time threshold in SQL

I have a console app that will choose records based on if the user has chosen to be notified daily at a specific hour of the day as well as all records where the user has chosen hourly.
The job will run every 15 minutes.
How do I find a threshold of time between 5 minutes before and 5 minutes after the top of the hour?
This is my code
Declare #Now datetime
Declare #NowHour int
Declare #NowMinute int
Declare #NewNow nvarchar(50)
Set #Now = {fn Now()}
Set #NowHour = (SELECT DATENAME(hh, #Now))
Set #NowMinute = (SELECT DATENAME(mi, #Now))
Set #NewNow = Cast(Cast(#NowHour As nvarchar(2)) + ':' + Cast(#NowMinute As nvarchar(2)) as Time)
Select #Now, #NowHour, #NowMinute, #NewNow
Select * From vw_consumerAlerts
Where casexid not in
(Select casexid from alerthistory)
And Name = 'Always'
Or ([Hour] Between DateAdd(minute, -5, #NewNow) And DateAdd(minute, -5, #NewNow))
This is the error I'm getting
The data types time and datetime are incompatible in the greater than or equal to operator.
I got it, I had [Hour] and #NewNow swapped, now I get the correct results with:
(#NewNow Between DateAdd(minute, -5, [Hour]) And DateAdd(minute, 5, [Hour]))
Assuming you have defined #TheHour as being the hour in question with 00 minutes/seconds:
WHERE mydatecol BETWEEN DATEADD(minute, -5, #TheHour) AND DATEADD(minute, 5, #TheHour)
UPDATE
See this:
select 1
where cast('1/1/2010 1:04pm' as time)
between cast('1/1/2010 12:55pm' AS time)
and cast ('1/1/2010 1:05pm' as time)
time and datetime are different, so you need to cast your datetime to time as I've done in the crude example here.
So in your case:
Select * From vw_consumerAlerts
Where casexid not in
(Select casexid from alerthistory)
And Name = 'Always'
Or ([Hour] Between cast(DateAdd(minute, -5, #NewNow) as time)
And cast(DateAdd(minute, -5, #NewNow) as time))