Updating dates with random time - sql

I have a datetime column, all of them at 12:00 am. Is there a way to update them with random hours, minutes to nearest 1/2 hour while keeping the same date(day) value?
Update Activities set ActivityDate = ....

Here's one option using dateadd:
update Activities
set ActivityDate = DateAdd(minute,
30 * (abs(checksum(NewId())) % 47), ActivityDate);
SQL Fiddle Demo
And here's a good post about generating random numbers. Using that, multiple by 30 minutes to get to the nearest half hour.
Note, this uses % 47 since there are 1440 minutes in a day -- that divides into 48 potential half hour segments in that same day.

Related

Getting random time interval in postgreSQL

I need random interval time between 0 and (10 days and 5 hours).
My code:
select random() * (interval '10 days 5 hours')
from generate_series(1, 50)
It works like should, except a few strange results, like:
0 years 0 mons 7 days 26 hours 10 mins 1.353353 secs
The problem is 26 hours, it shouldn't be more than 23. And I never get 10 days, what I'd like to.
Intervals in Postgres are quite flexible, so hour values of greater than 23 do not necessarily roll over to days. Use jusify_interval() to return them to the normal "days" and "hours"."
So:
select justify_interval(random() * interval '10 day 5 hour')
from generate_series(1, 200)
order by 1 desc;
will return values with appropriate values for days, hours, minutes, and seconds.
Now, why aren't you getting intervals with more than 10 days? This is simple randomness. If you increase the number of rows to 200 (as above), you'll see them (in all likelihood). If you run the code multiple times, sometimes you'll see none in that range; sometimes you'll see two.
Why? You are asking how often you get a value of 240+ in a range of 245. Those top 5 hours account for 0.02% of the range (about 1/50). In other words a sample of 50 is not big enough -- any given sample of 50 random values is likely to be missing 1 or more 5 hour ranges.
Plus, without justify_interval(), you are likely to miss those anyway because they may show up as 9 days with an hours component larger than 23.
Try this:
select justify_hours(random() * (interval '245 hours'))
FROM generate_series(1, 50)
See Postgres Documentation for an explanation of the justify_* functions.
One option would be to use an interval of one hour, and then multiply by the random number between 0 and 1 coming from the series:
select random() * 245 * interval '1 hour'
from generate_series(1, 50);
I can see that the other answers suggest using justify_interval. If you just want a series of intervals between 0 and 245 hours (245 hours corresponding to 10 days and 5 hours), then my answer should suffice.

sql statement - would like to subtract 1 date from another and get the days hours and mins inbetween

I would like to subtract 1 date from another and get the days hours and mins in-between.
I know there is a DateDiff function, however it does not work with all 3 time values; days hours and mins. I would like this doable in an SQL statement. Currently I have the following.
SELECT id, pickupdateandtime, GETDATE() AS CurrentTime,
(DATEDIFF(day,GETDATE(),pickupdateandtime)) AS Days,
(DATEDIFF(hour,GETDATE(),pickupdateandtime)) AS Hours,
(DATEDIFF(minute,GETDATE(),pickupdateandtime)) AS Mins FROM orders
And it shows up like this:
If we can stick it all in 1 column that's fine too.
I agree with #AndyMcLaughlin about the use of the mod operator % here. It's very handy for this sort of thing. However, I have a general distrust of DATEDIFF. That function does not count the whole number of years (say) between two dates, but the number of year boundaries between them.
So DATEDIFF "thinks" the difference in years between 01-Jan-2000 and 01-Jan-2001 is the same as that between 31-Dec-2000 and 01-Jan-2001.
This is why #Michael saw a need to subtract 1 from #AndyMcLaughlin's results. Unfortunately, that doesn't always work, it will depend on the individual case.
As a rule, DATEDIFF works well when it's used against the smallest interval you are interested in. So if you are interested in years and simply want to separate one calendar year from another, it'll serve you well.
I think the smallest interval we are interested in here is minutes. So we can use DATEDIFF for that, but have to work upwards from there to hours and days:
select
mf.id,
mf.pickupdateandtime,
mf.CurrentTime,
--The divisions in the following lines simply
--truncate since all the numbers are integers
--but that works in our favour here
(mf.MinutesFull/(60*24)) as Days,
(mf.MinutesFull/60) % 24 as Hours,
mf.MinutesFull % 60 as Minutes
from
(
select
id,
pickupdateandtime,
getdate() as CurrentTime,
datediff(minute, getdate(), pickupdateandtime) as MinutesFull
from #orders
) mf
You need to use the mod operator % to remove whole days from hours and whole hours from minutes.
So you can do something like:
SELECT
id,
pickupdateandtime,
GETDATE() AS CurrentTime,
(DATEDIFF(day,GETDATE(),pickupdateandtime)) AS Days,
(DATEDIFF(hour,GETDATE(),pickupdateandtime) % 24) AS Hours,
(DATEDIFF(minute,GETDATE(),pickupdateandtime) % 60) AS Mins FROM orders

Optimization: How to get TimeId from time for each minute in a week?

I am creating a table which will have 2 columns:
Day_time (time from 1978-01-01 00:00:00 Sunday, till 1978-01-07 23:59:00.0 Saturday, Granularity: Minute)
Time_id (a unique id for each minute), to be populated
I have column one populated. I want to populate column two.
How I am doing it right now:
EXTRACT(dayofweek FROM day_time) * 10000 + DATEDIFF('minutes', TRUNC(day_time), day_time)
I basically want a function where I pass any date and it tells me where I am in a week. So, I need a function, just like the function above. Just more optimized, where I give a date and get a unique ID. The unique ID should repeat weekly.
Example: ID for Jan 1, 2015 00:00:00 will be same as Jan 8, 2015 00:00:00.
Why 1978-01-01? cuz it starts from a Sunday.
Why 10,000? cuz the number of minutes in a day are in four digits.
You can do it all in one fell swoop, without needing to extract the date separately:
SELECT DATEDIFF('minutes', date_trunc('week',day_time), day_time) which I'd expect to be marginally faster.
Another approach that I'd expect to be significantly faster would be converting the timestamp to epoch, dividing by 60 to get minutes from epoch and then taking the value modulus of 10,080 (for 60 * 24 * 7 minutes in a week).
SELECT (extract(epoch from day_time) / 60) % 10080
If you don't care about the size of the weekly index, you could also do:
SELECT (extract(epoch from day_time)) % 604800 and skip the division step altogether, which should make it faster still.

Firebird - Converting stored integer to time equivalent

I am currently working on a Firebird database which stores slots for a time (like appointments). In the data the timeslot is stored in an Integer format but is not the slot time.
Example:
Slot Time: 11am
Database Value: 660
The database value is represented as the number of minutes since midnight. So 11am is 660 minutes from midnight. Or 12noon is 720
Question How, in Firebird, can a convert this 660 to display as 1100 (still an integer) or 540 as 900 (basically 9am)?
What you have stored into database is minutes since start of the day. So you just divide with 60 to get hours. Keep in mind that in SQL if both arguments of the division are integers you'll get integer as an answer, not decimal! Something like following should work for you (assuming the number of minutes is stored to timeslot field):
SELECT
cast(timeslot / 60 as varchar(2)) ||
case
when mod(timeslot, 60) < 10 then '0'|| mod(timeslot, 60)
else mod(timeslot, 60)
end
FROM t
This should give you 1130 for 11:30 am, not 1150 (11,5 hours).
Also see the DATEADD function.
First off I'd store it in the database as a TIME column instead of a number of minutes. Note that on a technical level Firebird stores TIME as the number of 100 microseconds since midnight. However if you really want to store as number of minutes, then you can use:
From minutes to TIME using DATEADD:
DATEADD(x MINUTE TO TIME'00:00')
Time to minutes using DATEDIFF:
DATEDIFF(MINUTE FROM TIME'00:00' TO y)
So:
SELECT
DATEADD(660 MINUTE TO TIME'00:00'),
DATEDIFF(MINUTE FROM TIME'00:00' TO TIME'11:00')
FROM RDB$DATABASE
Will return: 11:00:00.000, 660

SQL simple selection of rows according to their time

I have a table with measures and the time this measures have been taken in the following form: MM/DD/YYYY HH:MI:SS AM. I have measures over many days starting at the same time every day.The datas are minute by minute so basically the seconds are always = 0. I want to select only the measures for the first 5 minutes of each day. I would have used the where statement but the condition would only be on the minutes and note the date is there a way to do this?
Thanks
You could try something like this:
SELECT * FROM SomeTable
WHERE
DATEPART(hh, timestamp_col) = 0 AND -- filter for first hour of the day
DATEPART(mm, timestamp_col) <= 5 -- filter for the first five minutes
Careful! 0 means midnight. If your "first hour" of the day is actually 8 or 9 AM then you should replace the 0 with an 8 or 9.