UNIX Timestamp in future mysql - mysql

I have a table that holds a few UNIX timestamps that are in the future, I need to find the ones that are older than NOW() or are within 10 minutes of being in the past.
Here's the query I have tried using to no avail
SELECT
TIME_TO_SEC(TIMEDIFF(NOW(), FROM_UNIXTIME(`expires`))) AS `time_diff`
FROM
`video_table`
WHERE
time_diff < NOW() OR time_diff > '-600'
Can anyone point me in the direction as to why this will not work?

The question is not too clear, but I'm trying to answer with a few scenarios.
This query will return all records already expired:
SELECT * FROM video_table WHERE expires < UNIX_TIMESTAMP()
And this will return all records that are about to expire (they will expire within 10 minutes):
SELECT * FROM video_table
WHERE expires>=UNIX_TIMESTAMP() AND expires<UNIX_TIMESTAMP() + 600
This will return all records in the future (they will expire later than 10 minutes from now):
SELECT * FROM video_table WHERE expires>UNIX_TIMESTAMP() + 600

time_diff will give you the difference between NOW() and your expires column. What you want is to actually check if NOW()<expires (time_diff < 0) or if it's (NOW()+600s < expires) (time_diff < 600). So it's enough to check the latter:
SELECT
TIME_TO_SEC(TIMEDIFF(NOW(), FROM_UNIXTIME(`expires`))) AS `time_diff`
FROM
`video_table`
HAVING
`time_diff` < 600

DROP TABLE IF EXISTS my_table;
CREATE TABLE my_table (id INT NOT NULL AUTO_INCREMENT PRIMARY KEY,expires INT NOT NULL);
INSERT INTO my_table(expires) VALUES
(1442075399),
(1442075499),
(1442075599),
(1442075699),
(1442076106),
(1442076206),
(1442076306),
(1442076406);
SELECT UNIX_TIMESTAMP();
+------------------+
| UNIX_TIMESTAMP() |
+------------------+
| 1442075727 |
+------------------+
SELECT * FROM my_table WHERE expires - 600 < UNIX_TIMESTAMP();
+----+------------+
| id | expires |
+----+------------+
| 1 | 1442075399 |
| 2 | 1442075499 |
| 3 | 1442075599 |
| 4 | 1442075699 |
| 5 | 1442076106 |
| 6 | 1442076206 |
| 7 | 1442076306 |
+----+------------+

You can use DATE_ADD to get a time in the future:
SELECT UNIX_TIMESTAMP() - `expires` AS `time_diff`
FROM `video_table`
WHERE expires < UNIX_TIMESTAMP(DATE_ADD(NOW(), INTERVAL 10 MINUTE))

I am not quite sure I understand what you are trying to do, if you create a variable that will give the present time and than run your query as a less than or equal to clause it should work.
Here is an example
$t=time();
SELECT * FROM video_table
WHERE column_holding_unix_time<=$t;
I hope this helps

Related

How to order records by hours from 7 to 6:55?

How to sort records in mysqli by a custom start time:
For example in the table below i want to sort by date with the exception that the 'start' of every day is to be 7AM and not 12AM.
This seems like a trivial order by on the concatenated values of date and time
drop table if exists t;
create table t
(id int auto_increment primary key, time time, dt date);
insert into t(dt,time) values
('2019-10-15' ,'05:00:00'),
('2019-10-16' ,'06:55:00'),
('2019-10-15' ,'22:00:00'),
('2019-10-15' ,'07:55:00');
select * from t
order by concat(dt,time);
+----+----------+------------+
| id | time | dt |
+----+----------+------------+
| 1 | 05:00:00 | 2019-10-15 |
| 4 | 07:55:00 | 2019-10-15 |
| 3 | 22:00:00 | 2019-10-15 |
| 2 | 06:55:00 | 2019-10-16 |
+----+----------+------------+
4 rows in set (0.00 sec)
If this is not what you want then you need to put a bit more work into the question.
As mentioned by you in example https://imgur.com/a/IS7tupp, you need your tasklist to start at 7AM.
Please check and see if this works for you.
Sqlfiddle link : http://sqlfiddle.com/#!9/4b725c/1
drop table if exists t;
create table t (id int auto_increment primary key, time time);
insert into t(time) values
('00:05:00'),
('05:50:00'),
('07:00:00'),
('13:00:00'),
('19:00:00'),
('23:55:00');
select * from t
order by
case when time < '07:00:00' then 1 end asc, time;
#skelwa do you know how to order by sedcond column Date ?
so i have this sql and i need to add order by date also.. For example I need records from 2019-10-24 and after that 2019-10-25 from 7 to 6:55
select * from t
order by
case when time < '07:00:00' then 1 end asc, time;

MySQL doesn't use indexes in a SELECT clause subquery

I have an "events" table
table events
id (pk, auto inc, unsigned int)
field1,
field2,
...
date DATETIME (indexed)
I am trying to analyse holes in the trafic (the moments where there is 0 event in a day)
I try this kind of request
SELECT
e1.date AS date1,
(
SELECT date
FROM events AS e2
WHERE e2.date > e1.date
LIMIT 1
) AS date2
FROM events AS e1
WHERE e1.date > NOW() -INTERVAL 10 DAY
It takes a very huge amount of time
Here is the explain
+----+--------------------+-------+-------+---------------------+---------------------+---------+------+----------+-------------+
| id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
+----+--------------------+-------+-------+---------------------+---------------------+---------+------+----------+-------------+
| 1 | PRIMARY | t1 | range | DATE | DATE | 6 | NULL | 1 | Using where |
| 2 | DEPENDENT SUBQUERY | t2 | ALL | DATE | NULL | NULL | NULL | 58678524 | Using where |
+----+--------------------+-------+-------+---------------------+---------------------+---------+------+----------+-------------+
2 rows in set (0.00 sec)
Tested on MySQL 5.5
Why can't mysql use the DATE indexe? is it because of a subquery?
Your query suffers from the problem shown here which also presents a quick solution with temp tables. That is a mysql forum page, all of which I unearthed thru finding this Stackoverflow question.
You may find that the creation and populating such a new table on the fly yields bearable performance and is easy to implement with the range of datetimes now() less 10 days.
If you need assistance in crafting anything, let me know. I will see if I can help.
You are looking for dates with no events?
First build a table Days with all possible dates (dy). This will give you the uneventful days:
SELECT dy
FROM Days
WHERE NOT EXISTS ( SELECT * FROM events
WHERE date >= days.day
AND date < days.day + INTERVAL 1 DAY )
AND dy > NOW() -INTERVAL 10 DAY
Please note that 5.6 has some optimizations in this general area.

Grouping MySQL results by 7 day increments

Hoping someone might be able to assist me with this.
Assume I have the table listed below. Hosts can show up multiple times on the same date, usually with different backupsizes.
+------------------+--------------+
| Field | Type |
+------------------+--------------+
| startdate | date |
| host | varchar(255) |
| backupsize | float(6,2) |
+------------------+--------------+
How could I find the sum total of backupsize for 7 day increments starting with the earliest date, through the last date? I don't mind if the last few days get cut off because they don't fall into a 7 day increment.
Desired output (prefered):
+------------+----------+----------+----------+-----
|Week of | system01 | system02 | system03 | ...
+------------+----------+----------+----------+-----
| 2014/07/30 | 2343.23 | 232.34 | 989.34 |
+------------+----------+----------+----------+-----
| 2014/08/06 | 2334.7 | 874.13 | 234.90 |
+------------+----------+----------+----------+-----
| ... | ... | ... | ... |
OR
+------------+------------+------------+------
|Host | 2014/07/30 | 2014/08/06 | ...
+------------+------------+------------+------
| system01 | 2343.23 | 2334.7 | ...
+------------+------------+------------+-------
| system02 | 232.34 | 874.13 | ...
+------------+------------+------------+-------
| system03 | 989.34 | 234.90 | ...
+------------+------------+------------+-------
| ... | ... | ... |
Date format is not a concern, just as long as it gets identified somehow. Also, the order of the hosts is not a concern either. Thanks!
The simplest way is to get the earliest date and just count the number of days:
select x.minsd + interval floor(datediff(x.minsd, lb.startdate) / 7) day as `Week of`,
host,
sum(backupsize)
from listedbelow lb cross join
(select min(startdate) as minsd from listedbelow lb) x
group by floor(datediff(x.minsd, lb.startdate) / 7)
order by 1;
This produces a form with week of and host on each row. You can pivot the results as you see fit.
I'll assume that what you want is the sum of bakcupsize grouped by host and that seven-day interval you are talking about.
My solution would be something like this:
You need to define the first date, and then "create" a column with the date you want (the end of the seven-day period)
Then I would group it.
I think temporary tables and little tricks with temp variables are the best way to tackle this, so:
drop table if exists temp_data;
create temporary table temp_data
select a.*
-- The #d variable will have the date that you'll use later to group the data.
, #d := case
-- If the current "host" value is the same as the previous one, then...
when #host_prev = host then
-- ... if #d is not null and is within the seven-day period,
-- then leave the value of #d intact; in other case, add 7 days to it.
case
when #d is not null or a.startdate <= #d then #d
-- The coalesce() function will return the first not null argument
-- (just as a precaution)
else dateadd(coalesce(#d, a.startdate), interval +7 day)
end
-- If the current "host" value is not the same as the previous one,
-- then take the current date (the first date of the "new" host) and add
-- seven days to it.
else #d = dateadd(a.startdate, interval +7 day)
end as date_group
-- This is needed to perform the comparisson in the "case" piece above
, #host_prev := a.host as host2
from
(select #host_prev = '', #d = null) as init -- Initialize the variables
, yourtable as a
-- IMPORTANT: This will only work if you order the data properly
order by a.host, a.startdate;
-- Add indexes to the temp table, to make things faster
alter table temp_data
add index h(host),
add index dg(date_group)
-- OPTIONAL: You can drop the "host2" column (it is no longer needed)
-- , drop column host2
;
Now, you can get the grouped data:
select a.host, a.date_group, sum(a.bakcupsize) as backupsize
from temp_data as a
group by a.host, a.date_group;
This will give you the unpivoted data. If you want to build a pivot table with it, I recommend you take a look to this article, and/or read this question and its answers. In short, you'll have to build a "dynamic" sql instruction, prepare a statement with it and execute it.
Of course, if you want to group this by week, there's a simpler approach:
drop table if exists temp_data2;
create temporary table temp_data2
select a.*
-- The following will give you the end-of-week date
, dateadd(a.startdate, interval +(6 - weekday(a.startdate)) day) as group_date
from yourtable as a;
alter table temp_data
add index h(host),
add index dg(date_group);
select a.host, a.date_group, sum(a.bakcupsize) as backupsize
from temp_data as a
group by a.host, a.date_group;
I leave the pivot part to you.
So I was able to determine a solution that fit my needs using a procedure I created by putting together concepts from your recommended solutions as well as some other other solutions I found on this site. The procedure SUM's by 7 day increments as well as does a pivot.
DELIMITER $$
CREATE PROCEDURE `weekly_capacity_by_host`()
BEGIN
SELECT MIN(startdate) into #start_date FROM testtable;
SET #SQL = NULL;
SELECT
GROUP_CONCAT(DISTINCT
CONCAT(
'SUM(if(host=''',host,''', backupsize, 0)) as ''',host,''''
)
) INTO #SQL
FROM testtable;
SET #SQL = CONCAT('SELECT 1 + DATEDIFF(startdate, ''',#start_date,''') DIV 7 AS week_num
, ''',#start_date,''' + INTERVAL (DATEDIFF(startdate, ''',#start_date,''') DIV 7) WEEK AS week_start,
', #SQL,'
FROM testtable group by week_num'
);
PREPARE stmt FROM #SQL;
EXECUTE stmt;
DEALLOCATE PREPARE stmt;
END$$
DELIMITER ;
Output appears as follows:
mysql> call weekly_capacity_by_host;
+----------+------------+----------+----------+----------+----------+
| week_num | week_start | server01 | server02 | server03 | server04 |
+----------+------------+----------+----------+----------+----------+
| 1 | 2014-06-11 | 1231.08 | 37.30 | 12.04 | 68.17 |
| 2 | 2014-06-18 | 1230.98 | 37.30 | 11.76 | 68.13 |
| 3 | 2014-06-25 | 1243.12 | 37.30 | 8.85 | 68.59 |
| 4 | 2014-07-02 | 1234.73 | 37.30 | 11.77 | 67.80 |
| 5 | 2014-07-09 | 341.32 | 0.04 | 0.14 | 4.94 |
+----------+------------+----------+----------+----------+----------+
5 rows in set (0.03 sec)

MySQL query date with offset given

In MySQL I have a table node_weather:
mysql> desc node_weather;
+--------------------+--------------+------+-----+-------------------+-----------------------------+
| Field | Type | Null | Key | Default | Extra |
+--------------------+--------------+------+-----+-------------------+-----------------------------+
| W_id | mediumint(9) | NO | PRI | NULL | auto_increment |
| temperature | int(10) | YES | | NULL | |
| humidity | int(10) | YES | | NULL | |
| time | timestamp | NO | | CURRENT_TIMESTAMP | on update CURRENT_TIMESTAMP |
Now what I need to do is the following: for every two hours of the current day (00:00:00, 02:00:00, ..., 24:00:00) I want to get a temperature. Normally the query could be like that:
mysql> SELECT temperature
-> FROM node_weather
-> WHERE date(time) = DATE(NOW())
-> AND TIME(time) IN ('00:00:00','02:00:00','04:00:00','06:00:00','08:00:00','10:00:00','12:00:00','14:00:00','16:00:00','18:00:00','20:00:00','22:00:00','24:00:00');
In the ideal case, I should get a result as 12 rows selected and everything would be fine. But there are two problems with it:
The table does not include the data for thw whole day, so for example the temperature for the time '24:00:00' is missing. In this case, I would like to return NULL.
The table sometimes record the data with the timestamp like '10:00:02' or '09:59:58', but not '10:00:00'. To resolve this case, I would like to add the offset to all the values in IN expression (something like that ('10:00:00' - offset, '10:00:00' + offset)) and it would select always just ONE value (no matter which one) from this range.
I know it is kind of awkard, but that is how my boss wants it. Thanks for help!
Okay, a bit more precise than what I wrote in comments:
EDIT: Had a bug. Hopefully this doesn't.
SELECT
time,
deviation,
hour,
temperature
FROM (
SELECT
time,
ROUND(HOUR(time) / 2) * 2 AS hour,
IF(HOUR(time) % 2,
3600 - MINUTE(time) * 60 - SECOND(time),
MINUTE(time) * 60 + SECOND(time)
) AS deviation,
temperature
FROM node_weather
WHERE DATE(time) = DATE(NOW())
ORDER BY deviation ASC
) t
GROUP BY hour
ORDER BY
hour ASC
Basically, group on intervals like 09:00:00 - 10:59:59 (by rounding hour/2), then sort ascending by those intervals, and within the interval by the distance to the center of the interval (so we choose 10:00:00 over 09:00:00 or 10:59:59).

MySQL check if two date range overlap with input

I need to check if two dates over lap with another two dates in my database.
My database looks like this
+----+--------------+------------+------------+
| id | code | StartDate | EndDate |
+----+--------------+------------+------------+
| 1 | KUVX-21-40 | 2013-10-23 | 2013-11-22 |
| 2 | UEXA286-1273 | 2013-10-30 | 2013-11-29 |
| 3 | UAJFAU-2817 | 2013-10-21 | 2013-11-20 |
| 4 | KUVX-21-40 | 2013-10-30 | 2013-11-29 |
+----+--------------+------------+------------+
In my query i specify the scope: A start date and an enddate
Lets asign them as follows:
ScopeStartDate = "2013-10-1"
ScopeEndDate = "2013-11-26"
Above should return me all of the records, since the all overlapse the timespan.
However I cannot get a query working :/
I've tried the following query with no luck:
WHERE
(
(StartDate < ScopeStartDate AND StartDate > ScopeStartDate)
OR
(StartDate > ScopeStartDate AND EndDate < ScopeEndDate )
)
This returns me two results:
1 and 3
what am I doing wrong?
I believe the following condition matches every possible overlapping case.
WHERE
(
(ScopeStartDate <= EndDate AND ScopeEndDate >= StartDate)
)
except if you declare illogic timespans (for example, those which end before starting)
This is an old thread, but use BETWEEN. This is an excerpt from my timeclock, pls modify to your needs...
$qs = "SELECT COUNT(*) AS `count` FROM `timeclock` WHERE `userid` = :userid
AND (
(`timein` BETWEEN :timein AND :timeout OR `timeout` BETWEEN :timein AND :timeout )
OR
(:timein BETWEEN `timein` AND `timeout` OR :timeout BETWEEN `timein` AND `timeout`)
);";
This is just the where clause. Given InputStartDate and InputEndDate are given by user input, and DataStartDate and DataEndDate are the datetime values in the table:
where ((DataEndDate > InputStartDate) and (DataStartDate < InputEndDate))
You can cover all date overlapping cases even also when toDate in database can possibly be null as follows:
SELECT * FROM `tableName` t
WHERE t.`startDate` <= $toDate
AND (t.`endDate` IS NULL OR t.`endDate` >= $startDate);
This will return all records that overlaps with the new start/end dates in anyway.