I have mysql column time(3) and it's storing good value of time..
but then I want to sum two times it converts to bad time format;
I have two records:
id | time
---|-----------
1 | 00:00:15.490
2 | 00:02:14.900
So in real I shoud get: 00:02:30.390
but I get 230.390
is anyway to get correct answer from Mysql?
P.S. I am using php for functions but dont want to use it, unless there is other way.
Need to sum times with MILLISECONDS
for now I am using query SELECT SUM(time) AS total_time FROM times WHERE 1
Provided your table definition is something like this:
create table test (
id integer,
`time` time(3) -- important to specify precision
);
You can do this:
select time(sum(`time`))
from test;
note: requires mysql 5.6+
edit
Actually, time is the wrong function to use, as it doesn't have many smarts.
use sec_to_time instead, ie:
select sec_to_time(sum(`time`))
from test;
time extracts a time value, sec_to_time calculates a time value -- ie, time(70) returns NULL because there's no valid time that has 70 seconds, where as sec_to_time will correctly return '00:01:10' for the same input
edit
Turns out i'm still wrong. Lets try treating the milliseconds separately to the rest of the time:
select sec_to_time(sum(time_to_sec(`time`)) + sum(microsecond(`time`))/1000000)
from test;
Wrap your outputted result with the time function. So:
time(sum(`time`))
where time is the time function and 'time' is your summed column.
Related
I am running many energy readers which collects data with intervals of 5min. To get power used between two time stamps, I need to subtract older data from the newer data.
I am new to SQl, so I would like to ask what SQL syntax do I need to use to get a total sum between two Values.
Database Structure example:
Thank you very much.
You would typically use window function lead() or lag() - if your database supports that.
The following query puts on each row the difference with the previous value of the same equipment:
select
t.*,
t_energy_a - lag(t_energy_a) over(partition by meter_id order by dod) diff
from mytable t
I have to work with a postgres database 9.4 and i want to work with timestamp.
The first 'problem' is that when i create a timestamp column on postgres, i don't know what it does internally but when i query it returns '2010-10-30 00:00:00'
For me a timestamp is something like this 12569537329 (unix timestamp).
I say that because is a integer or a float, it's way easier for computer to deal comparing to string, and each country has his own time format, with unix timestamp is a number and end of story.
Querying from php the result is a string, so i have to make a bunch juggling and because of time zone, day light saving and other things something might could gone wrong.
I searched a lot of and can't find a way to work with unix timestamp on postgresql.
Can someone explain if there a way, or the right way to work and get as close as possible to unix timestamp.
UPDATE
One thing that i found that it gonna help me and it take a long time to discover that is possible on postgresql is change the Interval Output.
pg manual
In php the date interval for month is 'month' for pg is 'mon' on php it will understand mon as monday.
I think that if you have to juggle too much you are doing it wrong.
Gladly postgres let us to change that behavior for session or permanently.
So setting intervalstyle to iso_8601 it will work as php iso_8601 and will output P1M
Just convert the unix time_t to/from a timestamp, and use that in postgres:
CREATE TABLE omg
( seq SERIAL NOT NULL PRIMARY KEY
, stampthing TIMESTAMP WITH TIME ZONE DEFAULT CURRENT_TIMESTAMP
);
INSERT INTO omg(stampthing) SELECT now();
INSERT INTO omg(stampthing) VALUES
('epoch'::timestamptz )
, ('epoch'::timestamptz + 12569537329 * '1 second'::interval)
;
SELECT stampthing
, DATE_PART('epoch',stampthing) AS original
FROM omg;
Output:
CREATE TABLE
INSERT 0 1
INSERT 0 2
stampthing | original
-------------------------------+------------------
2016-01-20 16:08:12.646172+01 | 1453302492.64617
1970-01-01 01:00:00+01 | 0
2368-04-24 20:08:49+02 | 12569537329
(3 rows)
If you just query a timestamp column in postgres, you'll get a formatted date. If you prefer the unix timestamp integer you can either cast it when you return it using a syntax like
select extract(epoch from '2011-11-15 00:00:00+01'::timestamp with time zone)::integer;
If you do this a lot, you may make a view with the extract.
or you can define your timestamp column as an integer and store your data using the extract()
i want to minus purchase date with datenow. i have table named count_sec :
|user_id| purchasedate |second|
| 1 |2015-06-06 08:36:05| |
| 2 |2015-06-06 08:36:15| |
example time now is 2015-06-06 08:37:00
what is the code if i am want the code to update the second to:
|user_id| purchasedate |second|
| 1 |2015-06-06 08:36:05| 55 |
| 2 |2015-06-06 08:36:15| 45 |
thank you
EDIT
i have already create this php, but the code is not work, how to fix?
<?php
require 'database/db.php';
$selectprchsdate = $mysqli->query("SELECT purchasedate FROM count_sec");
$row = mysqli_fetch_assoc($selectprchsdate);
$date = date('Y-m-d H:i:s');
$result = $date - $row['purchasedate'];
$mysqli->query("UPDATE count_sec
SET second = '".$result."'");
?>
In PHP you can use
// get current date and time
$now = new DateTime();
// create DateTime object for purchase date
$purchaseDate = DateTime::createFromFormat('Y-m-d H:i:s', $row['purchasedate']);
// calculate seconds
$seconds = $now->getTimeStamp() - $purchaseDate->getTimeStamp();
But the SQL solution suits this question better.
Try with the SQL query:
SELECT UNIX_TIMESTAMP(NOW()) - UNIX_TIMESTAMP(purchasedate) as second from countsec
or this:
SELECT TO_SECONDS(NOW()) - TO_SECONDS(purchasedate) as second from countsec;
From MySQL Date and Time Functions
I am not understanding why you need to store this in a column in the table. As soon as it's stored, the value is old, and it will need to be updated again. (Don't do this.) But setting that issue aside for a moment...
As to why your code isn't "working"... your UPDATE statement is updating every row in the table. You've previously fetched one row from the table, and then calculated one value, and then the UPDATE statement doesn't have a WHERE clause to identify which row(s) you want to update, so every row gets updated with the same value. That's a big part of why your code isn't working.
And, there's no need to run a SELECT statement before you run an UPDATE. If you want to update all rows in the table, you set the column to an expression that returns the number of seconds between the current date and time and the date and time stored in purchasedate column.
One convenient way to do that is to use the UNIX_TIMESTAMP function to convert each of the DATETIME values into an integer value (number of seconds), and subtract them. For example:
UPDATE count_sec
SET `second` = UNIX_TIMESTAMP(NOW()) - UNIX_TIMESTAMP(purchasedate)
As an alternative, you could use the TIMESTAMPDIFF function for an equivalent result:
UPDATE count_sec
SET `second` = TIMESTAMPDIFF(SECOND,NOW(),purchasedate)
But back to the issue of why this is wrong. You do not want to store second column in the table.
When you run a SELECT statement to return a row from the table, the value in this column is going to old.
Instead, you could just return a calculated value, calculated as of the time the SELECT statement runs, by including one of those expressions in the SELECT list. For example:
SELECT user_id
, purchasedate
, UNIX_TIMESTAMP(NOW()) - UNIX_TIMESTAMP(purchasedate) AS `calc_second`
, `second` AS `old_stored_value`
FROM count_sec
ORDER BY user_id
The point I'm trying to emphasize here... do not store the second value in the table. You'll be chasing it, and continuously updating every row in table, whether that's every five minutes or every five seconds. And the stored value is always going to be "old".
Why do you need that? If you want to find out which rows in the table have second between 60 and 120, for example, if you intend to run this query:
SELECT user_id
FROM count_sec
WHERE second > 120
AND second <= 60
You could just as easily rewrite that based on purchasedate
SELECT user_id
FROM count_sec
WHERE purchasedate > NOW() - INTERVAL 120 SECOND
AND purchasedate <= NOW() - INTERVAL 60 SECOND
And, you won't be "chasing" continuous updates of the rows in the table, generating rollbackup, recording changes in the InnoDB log, writing the UPDATE statements in the binary logs. If you are running replication slaves, those statements have to be read from the log and re-executed on the slaves. All in all, storing second is just a poor design choice.
You can use TIMESTAMPDIFF() function like below. See Documentation
SELECT TIMESTAMPDIFF(SECOND, NOW(), purchasedate)
from count_sec;
(OR) if you want to UPDATE
UPDATE count_sec SET `second` = TIMESTAMPDIFF(SECOND, NOW(), purchasedate);
Per your comment, if you want to delay for 5 minutes then either you can use
SLEEP(seconds) function
(OR)
Wrap your updation code in a stored procedure and run that in every 5 minutes (probably using some scheduler job)
Using PHP to access mySQL.
I've got 10,000+ records, each of which has a Start-time and an End-time.
I'll want to work with these records a lot, so I'd like to understand how I can optimize queries as I write PHP functions to explore the data.
This first one, I want the average elapsed time over all records, i.e. the average of all (end minus start).
[EDIT]
Apologies: the question is: can I write a single query that will return the average of all timediffs of all my records? Or do I do my averaging in PHP after getting the TIMEDIFFS back (in a loop of 10,000 iterations)?
If I can do it in the mySQL query, how do I construct it? Clearly, it will involve TIMEDIFF() and AVG(), but I'm not sure if I can do it in one query or if I need more.
This is malformed:
SELECT AVG(SELECT TIMEDIFF(startdatetime,enddatetime) from myTable) from myTable
Assume this is my table:
myTable:
ID startdatetime enddatetime
1 2014-05-06 12:31:00 1 2014-05-06 12:41:00
2 2014-05-06 12:51:00 1 2014-05-06 12:55:00
I want to get back the average: (41-31)+(55-51)/2 = 7
(I imagine I'll have to convert the elapsed time to seconds, then average it, then convert it back to minutes.)
Ah OK. Once I figured out what I was after, the searching around got a lot easier. I've been able to piece together this:
SELECT SEC_TO_TIME(AVG(TIME_TO_SEC(TIMEDIFF(enddatetime,startdatetime)))) from myTable WHERE (enddatetime IS NOT NULL AND startdatetime IS NOT NULL)
I am querying data from a database, and the query clause varies with the day.
In other words, I want to get data in one-day unit by counting seconds in unix timestamps.
So, what I did for one-day-query is,
SELECT IDnum, Timestamp FROM table_name
WHERE CONVERT(Timestamp, UNSIGNED INTEGER) >= ($start_tim-86400*($i+1))
AND CONVERT(Timestamp, UNSIGNED INTEGER) < ($start_time-86400*$i)
because Timestamp attribute in table is varchar(32), I used CONVERT() in where clause to convert it to int, and compare with int type of 86400.
This query clause works so far, but it takes at least 5 mins in that I set ini_set('max_execution_time', 300). And after 5 mins, it showed
"Fatal error: Maximum execution time of 420 seconds exceeded in C:\www\LineChartOne\generateJSONdata.php on line 90", and still not complete.
My question is why it need so much time and, because I used function call in the "where clause"? Or something wrong with the "where clause", otherwise it should not run so slowly.
I'm guessing that the CONVERT() is super inefficient. Use UNIX_TIMESTAMP() or FROM_UNIXTIME() or date functions like DATE_SUB() or DATE_DIFF() to compare the dates.
If it still takes forever then either there's something wrong and you don't have tens of millions of rows then it is likely that:
Your PHP code is inefficient.
There's more to this query than what you're showing.
Your web and or mySQL servers are under heavy load from other users.
Edit:
Sweet jesus, the code in your comment makes my brain itch. Also I just now realized that your Timestamp column is a VARCHAR and not a TIMESTAMP. Bad user. Do not store numbers or dates as strings. Go sit in the corner.
Option 1: Make it an INT. [works with your existing code]
Option 2: Make it a DATETIME. [generally more flexible]
Things your are not getting:
FROM_UNIXTIME() converts an integer timestamp to a DATETIME type. If you feed it a string it will do an implicit conversion. [conversions are slow]
UNIX_TIMESTAMP() takes a date string, DATE, or DATETIME and returns an integer.
The code you gave UNIX_TIMESTAMP(FROM_UNIXTIME(Timestamp)) converts the string to an int to a date back to an int. The documentation is here, read up on it.
The vast majority of the reason why your query takes so long is because mySQL has to convert all of the values in Timestamp from VARCHAR to INTEGER. Change the column type and you can do simple integer comparisons which will be worlds faster.
A much smaller performance gain can be had by pre-computing the expression $start_time-86400*($i+1) in PHP. mySQL should optimize to evaluate only once, but the optimizer can do funky things when your queries become more complex and it might start computing this for each row.
The mysql query parser is struggling with converting those columns, you need to use the correct data types for the values you are storing, ie: int for int, varchar for strings, datetime etc....
ini_set('max_execution_time', 300); //300 seconds = 5 minutes
Place this at the top of your PHP script and let your script loose!
Taken from Increase PHP Script Execution Time Limit Using ini_set()