Mysql insert random datetime in a given datetime range - mysql

With SQL , Can I insert random datetime values in a column giving a range?
For example, given a range of 2010-04-30 14:53:27 to 2012-04-30 14:53:27
I'm getting confused with the range part. as i will have just done this
INSERT INTO `sometable` VALUES (RND (DATETIME()))

Here is an example that should help:
INSERT INTO `sometable` VALUES(
FROM_UNIXTIME(
UNIX_TIMESTAMP('2010-04-30 14:53:27') + FLOOR(0 + (RAND() * 63072000))
)
)
It uses the date 2010-04-30 14:53:27 as the base, converts that to a Unix timestamp, and adds a random number of seconds from 0 to +2 years to the base date and converts it back to a DATETIME.
It should be pretty close but over longer time periods leap years and other adjustments will throw it off.

This should work nicely:
SET #MIN = '2010-04-30 14:53:27';
SET #MAX = '2012-04-30 14:53:27';
SELECT TIMESTAMPADD(SECOND, FLOOR(RAND() * TIMESTAMPDIFF(SECOND, #MIN, #MAX)), #MIN);
TIMESTAMPDIFF is used to determine the number of seconds in the date range. Multiply this by a random number between 0-1 results in a random number between 0 and the number of seconds in the range. Adding this random number of seconds to the lower bound of the range results in a random date between the data range bounds.

This works perfectly even for leap years:
select from_unixtime(
unix_timestamp('2000-1-1') + floor(
rand() * (
unix_timestamp('2010-12-31') - unix_timestamp('2000-1-1') + 1
)
)
)
The idea is simple: Just take a random timestamp between the two timestamps, then convert it to a datetime using from_unixtime. This way you can ensure that each option has equal probability.

Easiest way out:
INSERT INTO `sometable` VALUES (SELECT timestamp('2010-04-30 14:53:27') - INTERVAL FLOOR( RAND( ) * 366) DAY);

Just try :
SELECT TIMESTAMP('2012-04-30 14:53:27')-INTERVAL RAND()*365*2 DAY INTO tbl_name;

SET #MIN = '2019-06-29 00:53:27';
SET #MAX = '2019-06-29 13:53:27';
UPDATE tablename
SET columnname = TIMESTAMPADD(SECOND, FLOOR(RAND() * TIMESTAMPDIFF(SECOND, #MIN, #MAX)), #MIN)
WHERE `columnname` = condition

This worked for me but my issue was a bit different. I had to assign certain values in a column to a random datetime.
UPDATE Tablename
SET columnName = addtime(concat_ws(' ','2018-07-25' + interval rand()*2 day
,'00:00:00'),sec_to_time(floor(0 + (rand() * 86401))))
WHERE columnName = condition;

It's an old thread but still.. In my case I needed to generate random date in format like this : 2017-01-01.
If anyone will need it I have used #drew010 solution and formatted date with DATE_FORMAT.
Here is my code :
SELECT DATE_FORMAT(FROM_UNIXTIME(UNIX_TIMESTAMP('2015-01-01') + FLOOR(0 + (RAND() * 63072000))), '%Y-%m-%d');

Use following dynamic query.
SET #MIN = NOW() - INTERVAL 2 MONTH;
SET #MAX = now();
select TIMESTAMPADD(SECOND, FLOOR(RAND() * TIMESTAMPDIFF(SECOND, #MIN, #MAX)), #MIN)
Thanks to #sapna-bhayal

Related

Timestampdiff excluding some hours and weekend mysql [duplicate]

I have a field of time Timestamp in my MySQL database which is mapped to a DATE datatype in my bean. Now I want a query by which I can fetch all records in the database for which the difference between the current timestamp and the one stored in the database is > 20 minutes.
How can I do it?
What i want is:
SELECT * FROM MyTab T WHERE T.runTime - now > 20 minutes
Are there any MySQL functions for this, or any way to do this in SQL?
If you have MySql version above 5.6 you could use TIMESTAMPDIFF(unit,datetime_expr1,datetime_expr2) something like
select * from MyTab T where
TIMESTAMPDIFF(MINUTE,T.runTime,NOW()) > 20
MySql version >=5.6
I am using below code for today and database date.
TIMESTAMPDIFF(MINUTE,T.runTime,NOW()) > 20
According to the documentation, the first argument can be any of the following:
MICROSECOND
SECOND
MINUTE
HOUR
DAY
WEEK
MONTH
QUARTER
YEAR
ROUND(time_to_sec((TIMEDIFF(NOW(), "2015-06-10 20:15:00"))) / 60);
Try this one:
select * from MyTab T where date_add(T.runTime, INTERVAL 20 MINUTE) < NOW()
NOTE: this should work if you're using MySQL DateTime format. If you're using Unix Timestamp (integer), then it would be even easier:
select * from MyTab T where UNIX_TIMESTAMP() - T.runTime > 20*60
UNIX_TIMESTAMP() function returns you current unix timestamp.
You can try this:
SELECT * FROM MyTab T WHERE CURRENT_TIMESTAMP() > T.runTime + INTERVAL 20 MINUTE;
The CURRENT_TIMESTAMP() is a function and returns the current date and time. This function works From MySQL 4.0
If you have MySql version prior than 5.6 you don't have TIMESTAMPDIFF. So,I wrote my own MySql function to do this. Accets %i or %m for minutes and %h for hours. You can extend it.
Example of usage:
SELECT MYTSDIFF('2001-01-01 10:44:32', '2001-01-01 09:50:00', '%h')
Here goes the function. Enjoy:
DROP FUNCTION IF EXISTS MYTSDIFF;
DELIMITER $$
CREATE FUNCTION `MYTSDIFF`( date1 timestamp, date2 timestamp, fmt varchar(20))
returns varchar(20) DETERMINISTIC
BEGIN
declare secs smallint(2);
declare mins smallint(2);
declare hours int;
declare total real default 0;
declare str_total varchar(20);
if date1 > DATE_ADD( date2, interval 30 day) then
return '999999.999'; /* OUT OF RANGE TIMEDIFF */
end if;
select cast( time_format( timediff(date1, date2), '%s') as signed) into secs;
select cast( time_format( timediff(date1, date2), '%i') as signed) into mins;
select cast( time_format( timediff(date1, date2), '%H') as signed) into hours;
set total = hours * 3600 + mins * 60 + secs;
set fmt = LOWER( fmt);
if fmt = '%m' or fmt = '%i' then
set total = total / 60;
elseif fmt = '%h' then
set total = total / 3600;
else
/* Do nothing, %s is the default: */
set total = total + 0;
end if;
select cast( total as char(20)) into str_total;
return str_total;
END$$
DELIMITER ;

Why is "INTERVAL" not a valid syntax in IF statement

I have a IF THEN ELSE statement in one of my stored prodecures.
if (DAYOFWEEK((SELECT DATE_ADD(_todaydate, INTERVAL (_sign * offset.value) DAY)))=7)
then
SELECT DATE_ADD(daytemp, INTERVAL (_sign * offset.value + 2) DAY) into `day`;
elseif (DAYOFWEEK((SELECT DATE_ADD(_todaydate, INTERVAL _sign * offset.value DAY)))=1)
then
SELECT DATE_ADD(daytemp, INTERVAL (_sign * offset.value + 1) DAY) into `day`;
else
Select (SELECT DATE_ADD(_todaydate, INTERVAL _sign * offset.value DAY)) into `day`;
END if;
where _todaydate is today's date,_sign is either +1 or -1 depending on if you want to find days in future or past and the offset is a number int showing how many days from _todaydate.
The query is meant to return me working day either in past or future depending upon the _sign * offset.value, but the problem is that sql returns me an error saying that "unexpected INTERVAL (interval) in the if statement"
I am not sure why I am getting this problem because the query it self looks fine to me. Can some one please see what I am missing...
Additional Information:
I have this IF statement in a "Select From" statement, Could that be the case of that this error is happening?
Shouldn't your IF statement be like below
if (SELECT DAYOFWEEK(DATE_ADD(_todaydate, INTERVAL (_sign * offset.value) DAY))=7)
Moreover, I see that you are repeating the same condition multiple times, eventually executing the same query multiple times. Instead have this query executed before and store the value to a local variable and use that local variable in your conditional statement rather; which would be much efficient.
Wouldn't the code be much easier to debug and understand, if we avoided repeating long expressions, wrote something like this (to accomplish what it looks like we are trying to achieve):
DECLARE _dow INT;
DECLARE _inc INT;
SELECT DAYOFWEEK(DATE_ADD(_todaydate, INTERVAL (_sign * offset.value) DAY)) INTO _dow ;
CASE _dow
WHEN 7 THEN SET _inc = 2;
WHEN 1 THEN SET _inc = 1;
ELSE SET _inc = 0;
END CASE;
SELECT DATE_ADD(daytemp, INTERVAL (_sign * offset.value + _inc) DAY) INTO `day`;
To answer the question you asked, "why is INTERVAL not a valid syntax in IF statement"...
I'm not aware of any restriction in MySQL stored programs that prohibits the use of the keyword INTERVAL within an IF statement. Obviously, the INTERVAL keyword isn't part of the IF construct; the keyword is only valid in the context of some expressions.
FOLLOWUP
I notice that the rewrite above is not equivalent to the original. In the original, under the ELSE condition, it's DATE_ADD(_todaydate,. That differs from the other two conditions, where it's DATE_ADD(daytemp
A slight re-write to accommodate that difference, adding another variable _bdt, allows us to still just use two SELECT statements...
DECLARE _bdt DATE;
DECLARE _dow INT;
DECLARE _inc INT;
SELECT DAYOFWEEK(DATE_ADD(_todaydate, INTERVAL (_sign * offset.value) DAY)) INTO _dow ;
CASE _dow
WHEN 7 THEN
SET _inc = 2;
SET _bdt = daytemp;
WHEN 1 THEN
SET _inc = 1;
SET _bdt = daytemp;
ELSE
SET _inc = 0;
SET _bdt = _todaydate;
END CASE;
SELECT DATE_ADD(_bdt, INTERVAL (_sign * offset.value + _inc) DAY) INTO `day`;

Select less and less records over time?

I'd like to write a query or stored procedure to retrieve less and less records over time from a relational database.
Think of this like populating the Google Finance stock chart: The past few days will have all ticks fit the day, and the further you go back, less and less ticks are displayed on each date. All ticks will show for today, 50% of ticks will show for one week ago, 30% for one month ago, and 10% for one year ago. Think of this like a gradient.
Is it possible to achieve this with one query? Or perhaps it would be necessary to use multiple queries? What might this look like?
Note that record ids are non-contiguous (there are gaps), but each record has a timestamp for determining order.
Also note that I am using MySQL.
Here is the structure of my table:
quotes
id
security_id
last_price
bid_price
ask_price
date
timestamp
trade_volume
cumulative_volume
average_volume
created_at
Sounds like you are looking for a constant set of records that represent the time-span. You can do so by defining a control date set.
Here's a sample query (doesn't account for weekends and holidays but that can be added):
POPULATE:
CREATE TABLE #quotes
(
id int identity(1,1)
,security_id VARCHAR(50)
,last_price FLOAT
,bid_price FLOAT
,ask_price FLOAT
,[date] DATETIME
,[timestamp] DATETIME
,trade_volume FLOAT
,cumulative_volume FLOAT
,average_volume FLOAT
,created_at DATETIME
)
DECLARE #i int
set #i = 100000
WHILE #i > 0
BEGIN
INSERT INTO #quotes (
security_id
,last_price
,bid_price
,ask_price
,[date]
,[timestamp]
,trade_volume
,cumulative_volume
,average_volume
,created_at
)
values( 'IBM US'
, 100.00 + RAND()
, 100.00 + RAND()
, 100.00 + RAND()
, DATEADD(MINUTE, -1* #i, GETDATE())
, DATEADD(MINUTE, -1* #i, GETDATE())
, 10000000.00 + RAND()*1000000.00
, 10000000.00 + RAND()*1000000.00
, 10000000.00 + RAND()*1000000.00
,getdate())
set #i= #i-1
END
You can change around the time span, but the following will give you around 1000 records that represent the set from start to finish.
DECLARE #StartDate DATETIME,
#EndDate DATETIME,
#j FLOAT,
#step FLOAT
set #StartDate = GETDATE()-20
SET #EndDAte = GETDATE()
set #j = 0.0
CREATE TABLE #TimeTable
(
IntervalDate DATETIME
)
--say you always want 1000 measures
--use the datediff value to define the step size:
select #step = DATEDIFF(MINUTE, #StartDate, #EndDate)/1000.0
WHILE #j < DATEDIFF(MINUTE, #StartDate, #EndDate)
BEGIN
INSERT #TimeTable (IntervalDate) VALUES (DATEADD(minute, #j, #StartDate))
SET #j = #j+#step
print #j
END
select security_id
,last_price
,bid_price
,ask_price
,[date]
,[timestamp]
,trade_volume
,cumulative_volume
,average_volume
,created_at
from #Quotes q
join #TimeTable t on dateadd(mi, datediff(mi, 0, q.date), 0) = dateadd(mi, datediff(mi, 0, t.IntervalDate), 0)

SQL Server - calculate elapsed time between two datetime stamps in HH:MM:SS format

I have a SQL Server table that has a "Time" column. The table is a log table the houses status messages and timestamps for each message. The log table is inserted into via a batch file. There is an ID column that groups rows together. Each time the batch file runs it initializes the ID and writes records. What I need to do is get the elapsed time from the first record in an ID set to the last record of the same ID set. I started toying with select Max(Time) - Min(Time) from logTable where id = but couldn't figure out how to format it correctly. I need it in HH:MM:SS.
SQL Server doesn't support the SQL standard interval data type. Your best bet is to calculate the difference in seconds, and use a function to format the result. The native function CONVERT() might appear to work fine as long as your interval is less than 24 hours. But CONVERT() isn't a good solution for this.
create table test (
id integer not null,
ts datetime not null
);
insert into test values (1, '2012-01-01 08:00');
insert into test values (1, '2012-01-01 09:00');
insert into test values (1, '2012-01-01 08:30');
insert into test values (2, '2012-01-01 08:30');
insert into test values (2, '2012-01-01 10:30');
insert into test values (2, '2012-01-01 09:00');
insert into test values (3, '2012-01-01 09:00');
insert into test values (3, '2012-01-02 12:00');
Values were chosen in such a way that for
id = 1, elapsed time is 1 hour
id = 2, elapsed time is 2 hours, and
id = 3, elapsed time is 3 hours.
This SELECT statement includes one column that calculates seconds, and one that uses CONVERT() with subtraction.
select t.id,
min(ts) start_time,
max(ts) end_time,
datediff(second, min(ts),max(ts)) elapsed_sec,
convert(varchar, max(ts) - min(ts), 108) do_not_use
from test t
group by t.id;
ID START_TIME END_TIME ELAPSED_SEC DO_NOT_USE
1 January, 01 2012 08:00:00 January, 01 2012 09:00:00 3600 01:00:00
2 January, 01 2012 08:30:00 January, 01 2012 10:30:00 7200 02:00:00
3 January, 01 2012 09:00:00 January, 02 2012 12:00:00 97200 03:00:00
Note the misleading "03:00:00" for the 27-hour difference on id number 3.
Function to format elapsed time in SQL Server
UPDATED:
Correctly calculate a timespan in SQL Server, even if more than 24 hours:
-- Setup test data
declare #minDate datetime = '2012-12-12 20:16:47.160'
declare #maxDate datetime = '2012-12-13 15:10:12.050'
-- Get timespan in hh:mi:ss
select cast(
(cast(cast(#maxDate as float) - cast(#minDate as float) as int) * 24) /* hours over 24 */
+ datepart(hh, #maxDate - #minDate) /* hours */
as varchar(10))
+ ':' + right('0' + cast(datepart(mi, #maxDate - #minDate) as varchar(2)), 2) /* minutes */
+ ':' + right('0' + cast(datepart(ss, #maxDate - #minDate) as varchar(2)), 2) /* seconds */
-- Returns 18:53:24
Edge cases that show inaccuracy are especially welcome!
DECLARE #EndTime AS DATETIME, #StartTime AS DATETIME
SELECT #StartTime = '2013-03-08 08:00:00', #EndTime = '2013-03-08 08:30:00'
SELECT CAST(#EndTime - #StartTime AS TIME)
Result: 00:30:00.0000000
Format result as you see fit.
The best and simple way:
Convert(varchar, {EndTime} - {StartTime}, 108)
Just like Anri noted.
Use the DATEDIFF to return value in milliseconds, seconds, minutes, hours, ...
DATEDIFF(interval, date1, date2)
interval REQUIRED - The time/date part to return. Can be one of the following values:
year, yyyy, yy = Year
quarter, qq, q = Quarter
month, mm, m = month
dayofyear = Day of the year
day, dy, y = Day
week, ww, wk = Week
weekday, dw, w = Weekday
hour, hh = hour
minute, mi, n = Minute
second, ss, s = Second
millisecond, ms = Millisecond
date1, date2 REQUIRED - The two dates to calculate the difference between
select convert(varchar, Max(Time) - Min(Time) , 108) from logTable where id=...
See if this helps. I can set variables for Elapsed Days, Hours, Minutes, Seconds.
You can format this to your liking or include in a user defined function.
Note: Don't use DateDiff(hh,#Date1,#Date2). It is not reliable! It rounds in unpredictable ways
Given two dates...
(Sample Dates: two days, three hours, 10 minutes, 30 seconds difference)
declare #Date1 datetime = '2013-03-08 08:00:00'
declare #Date2 datetime = '2013-03-10 11:10:30'
declare #Days decimal
declare #Hours decimal
declare #Minutes decimal
declare #Seconds decimal
select #Days = DATEDIFF(ss,#Date1,#Date2)/60/60/24 --Days
declare #RemainderDate as datetime = #Date2 - #Days
select #Hours = datediff(ss, #Date1, #RemainderDate)/60/60 --Hours
set #RemainderDate = #RemainderDate - (#Hours/24.0)
select #Minutes = datediff(ss, #Date1, #RemainderDate)/60 --Minutes
set #RemainderDate = #RemainderDate - (#Minutes/24.0/60)
select #Seconds = DATEDIFF(SS, #Date1, #RemainderDate)
select #Days as ElapsedDays, #Hours as ElapsedHours, #Minutes as ElapsedMinutes, #Seconds as ElapsedSeconds
Hope this helps you in getting the exact time between two time stamps
Create PROC TimeDurationbetween2times(#iTime as time,#oTime as time)
As
Begin
DECLARE #Dh int, #Dm int, #Ds int ,#Im int, #Om int, #Is int,#Os int
SET #Im=DATEPART(MI,#iTime)
SET #Om=DATEPART(MI,#oTime)
SET #Is=DATEPART(SS,#iTime)
SET #Os=DATEPART(SS,#oTime)
SET #Dh=DATEDIFF(hh,#iTime,#oTime)
SET #Dm = DATEDIFF(mi,#iTime,#oTime)
SET #Ds = DATEDIFF(ss,#iTime,#oTime)
DECLARE #HH as int, #MI as int, #SS as int
if(#Im>#Om)
begin
SET #Dh=#Dh-1
end
if(#Is>#Os)
begin
SET #Dm=#Dm-1
end
SET #HH = #Dh
SET #MI = #Dm-(60*#HH)
SET #SS = #Ds-(60*#Dm)
DECLARE #hrsWkd as varchar(8)
SET #hrsWkd = cast(#HH as char(2))+':'+cast(#MI as char(2))+':'+cast(#SS as char(2))
select #hrsWkd as TimeDuration
End

Calculating time difference between 2 dates in minutes

I have a field of time Timestamp in my MySQL database which is mapped to a DATE datatype in my bean. Now I want a query by which I can fetch all records in the database for which the difference between the current timestamp and the one stored in the database is > 20 minutes.
How can I do it?
What i want is:
SELECT * FROM MyTab T WHERE T.runTime - now > 20 minutes
Are there any MySQL functions for this, or any way to do this in SQL?
If you have MySql version above 5.6 you could use TIMESTAMPDIFF(unit,datetime_expr1,datetime_expr2) something like
select * from MyTab T where
TIMESTAMPDIFF(MINUTE,T.runTime,NOW()) > 20
MySql version >=5.6
I am using below code for today and database date.
TIMESTAMPDIFF(MINUTE,T.runTime,NOW()) > 20
According to the documentation, the first argument can be any of the following:
MICROSECOND
SECOND
MINUTE
HOUR
DAY
WEEK
MONTH
QUARTER
YEAR
ROUND(time_to_sec((TIMEDIFF(NOW(), "2015-06-10 20:15:00"))) / 60);
Try this one:
select * from MyTab T where date_add(T.runTime, INTERVAL 20 MINUTE) < NOW()
NOTE: this should work if you're using MySQL DateTime format. If you're using Unix Timestamp (integer), then it would be even easier:
select * from MyTab T where UNIX_TIMESTAMP() - T.runTime > 20*60
UNIX_TIMESTAMP() function returns you current unix timestamp.
You can try this:
SELECT * FROM MyTab T WHERE CURRENT_TIMESTAMP() > T.runTime + INTERVAL 20 MINUTE;
The CURRENT_TIMESTAMP() is a function and returns the current date and time. This function works From MySQL 4.0
If you have MySql version prior than 5.6 you don't have TIMESTAMPDIFF. So,I wrote my own MySql function to do this. Accets %i or %m for minutes and %h for hours. You can extend it.
Example of usage:
SELECT MYTSDIFF('2001-01-01 10:44:32', '2001-01-01 09:50:00', '%h')
Here goes the function. Enjoy:
DROP FUNCTION IF EXISTS MYTSDIFF;
DELIMITER $$
CREATE FUNCTION `MYTSDIFF`( date1 timestamp, date2 timestamp, fmt varchar(20))
returns varchar(20) DETERMINISTIC
BEGIN
declare secs smallint(2);
declare mins smallint(2);
declare hours int;
declare total real default 0;
declare str_total varchar(20);
if date1 > DATE_ADD( date2, interval 30 day) then
return '999999.999'; /* OUT OF RANGE TIMEDIFF */
end if;
select cast( time_format( timediff(date1, date2), '%s') as signed) into secs;
select cast( time_format( timediff(date1, date2), '%i') as signed) into mins;
select cast( time_format( timediff(date1, date2), '%H') as signed) into hours;
set total = hours * 3600 + mins * 60 + secs;
set fmt = LOWER( fmt);
if fmt = '%m' or fmt = '%i' then
set total = total / 60;
elseif fmt = '%h' then
set total = total / 3600;
else
/* Do nothing, %s is the default: */
set total = total + 0;
end if;
select cast( total as char(20)) into str_total;
return str_total;
END$$
DELIMITER ;