how to retrieve count from mysql between 2 hours - php

Consider the following table:
CREATE TABLE `trans` (
`transid` varchar(255) NOT NULL,
`affid` varchar(255) NOT NULL,
`timestamp` varchar(255) NOT NULL,
UNIQUE KEY `transid` (`transid`)
) ENGINE=MyISAM DEFAULT CHARSET=utf8;
and PHP code:
case "today":
$sale=[];
for ($i = 0 ; $i < 23 ; $i++) {
$hours[]= $i;
$clicks[$i]=$api["clicks"][$i];
}
break;
I want to add into the $sale array today's count of sales for each hour. Something like: $hours[5] = select count(*) from trans where .. date is between today's 04:59:59 - 06:00:00.

First of all, if you are trying to use unix timestamps for your timestamp field, stop it now. You are already making your life painful. Use a MySQL timestamp field. There are honestly very few use cases where it is a good idea to use a unix timestamp field.
If you had a timestamp field you could do something like
SELECT HOUR(`timestamp`) AS `hour`, SUM(`transid`) AS `transaction_count`
FROM trans
WHERE `timestamp` LIKE CONCAT(DATE(NOW()),'%')
GROUP BY `hour`
ORDER BY `hour` ASC
That would give you the sales count for every hour of the current day. Make sure you add an index on timestamp for optimal query performance.
If you don't have a timestamp, then you need to utilize extra FROM_UNIXTIME() conversions, which would prevent you from being able to use an index on timestamp

Something like this:
<?php
$from=strtotime("".date("Y-m-d")." 04:59:59");
$to=strtotime("".date("Y-m-d")." 06:00:00");
?>
"SELECT * FROM `your_table`
WHERE `date` > '".$from."'
AND `date` < '".$to."'"
maybe?
You can use gmdate() if you need the current UTC time instead of the local time which you get with date().

Related

How to fix reading from till to date and time mysql?

On my testpage i have 2 bootstrap datetime pickers.
When the user selects a start date/time and a end date/time and push the button the screen will be filled by data from sql database.
But i have trouble reading from the right time, date is no problem.
The code what i have is this.:
$date=$_POST['q'];
$date=explode(' ',$date);
echo "Date".': '.$date[0]."<br/>";
echo "Time".': '.$date[1]."<br/>";
$date1=$_POST['q1'];
$date1=explode(' ',$date1);
echo "Date".': '.$date1[0]."<br/>";
echo "Time".': '.$date1[1]."<br/>";
$a1 = $_POST['a1'];
$q = $date[0];
$q1 = $date1[0];
$q2 = $date[1];
$q3 = $date1[1];
$query = mysqli_query($conn,"SELECT *
FROM `metingen`
WHERE (Datum >= '$q' AND Datum <= '$q1')
and (Tijd >= '$q2' AND Tijd <= '$q3')
ORDER BY Id DESC");
Its not pritty but witout the tijd(time) its works great, with tijd(time) i miss data.
The date and time i split, as you can see , because the database what i want to use is not made by me, so the date is a seperated column and also time a seperated and both are also text.
if i echo the explode date/time a see.:
Date: 15-02-2019
Time: 01:00:32
Date: 16-02-2019
Time: 22:55:33
But the data what i get is from 15-2-2019 00:30:56 and till 15-2-2019 22:11:08
I don't see all the dates i miss dates from the 16 and i get dates before my start time.
I think i have something wrong in my sql rule but , i don't know what.
can somebody help me please.
This is my create and insert code of my table (i shorted it in a bit).:
CREATE TABLE `metingen` (
`Id` int(11) NOT NULL,
`Datum` varchar(255) DEFAULT NULL,
`Tijd` varchar(255) DEFAULT NULL,
) ENGINE=MyISAM DEFAULT CHARSET=utf8;
--
-- Gegevens worden geƫxporteerd voor tabel `metingen`
--
INSERT INTO `metingen` (`Id`, `Datum`, `Tijd`) VALUES
(1, '17-1-2019', '10:31:39'),
(4, '18-1-2019', '10:30:01'),
(40, '28-1-2019', '23:59:42'),
(41, '28-1-2019', '00:50:12'),
(42, '29-1-2019', '02:00:42'),
(49, '29-1-2019', '06:22:53'),
(56, '5-2-2019', '19:35:02'),
(236, '13-2-2019', '13:58:43')
ALTER TABLE `metingen`
ADD KEY `Id` (`Id`);
ALTER TABLE `metingen`
MODIFY `Id` int(11) NOT NULL AUTO_INCREMENT, AUTO_INCREMENT=319;
You should not store date and time as separate fields in your database. You should just combine them into one datetime field in your database. You should then insert and compare such datetime values in one of the supported literal formats, such as YYYY-MM-DD H:m:s
Now back to your original situation. The problem is that you require the time condition also when the table's date is strictly between the two extreme dates (not equal to either of them). In that case there should be no constraint on the time part: all times would be OK on such days.
So here is how the SQL would look:
SELECT *
FROM metingen
WHERE ( Datum > '$q' OR ( Datum = '$q' AND Tijd >= '$q2' ) )
AND ( Datum < '$q1' OR ( Datum = '$q1' AND Tijd <= '$q3' ) )
ORDER BY Id DESC
But again, this is not the best practice.
If you have stored your dates as varchar (not as date), using the D-M-YYYY format, while your input is DD-MM-YYYY, then it becomes even more complex (and slow):
SELECT *
FROM metingen
WHERE ( STR_TO_DATE(Datum, '%d-%m-%Y') > STR_TO_DATE('$q', '%d-%m-%Y')
OR ( STR_TO_DATE(Datum, '%d-%m-%Y') = STR_TO_DATE('$q', '%d-%m-%Y')
AND Tijd >= '$q2' ) )
AND ( STR_TO_DATE(Datum, '%d-%m-%Y') < STR_TO_DATE('$q1', '%d-%m-%Y')
OR ( STR_TO_DATE(Datum, '%d-%m-%Y') = STR_TO_DATE('$q1', '%d-%m-%Y')
AND Tijd <= '$q3' ) )
ORDER BY Id DESC
Another issue is that you inject strings that are posted to the page, and so they are user-driven. This represents a SQL Injection vulnerabilty. Instead you should use prepared statements and pass the datetime strings as parameters.

PHP mySQL Time Between Rows

Hello I am stuck on this. Looking to be able to pull the time between 2 start/stop rows from a mySQL database. My table looks like this
fillercdown_ndx | time | B3_4_5
1 | 2016-06-16 14:59:45 | 0
2 | 2016-06-16 15:03:11 | 1
Basically when its recorded as 0 the machine stopped and when the record is 1 the machine restarted. I need to be able to calculate the amount of time the machine was down between certain times like 8AM-5PM. Was going to use PHP to display it upon users time entered, but have no idea on the SQL command.
Anyone know the best way to be able to find this?
Create table
CREATE TABLE `fillercdown` (
`fillercdown_ndx` int(11) NOT NULL AUTO_INCREMENT,
`time` datetime DEFAULT NULL,
`B3_4_5` int(11) DEFAULT NULL,
PRIMARY KEY (`fillercdown_ndx`),
KEY `fillercdowntimendx` (`time`)
) ENGINE=InnoDB AUTO_INCREMENT=7 DEFAULT CHARSET=latin1
UPDATE:
There will be hundreds of these "start" and "stop" entries. My end all goal would be in php to give the user a small form asking them to provide a time range like 8AM-5PM and then be able to calculate all the time where the machine was "stopped" (which is when B3_4_5 is at 0). I just can't seem to figure out the right SQL call to get the time differences between each 0 and 1 and add them together between a set time range
This is what I am currently using to do the same thing it sounds like you're trying to do. I'm using PDO but this could be adapted fairly easily for mysqli if you need to use that. This depends on alternating off/on values by time. If there are any consecutive off or on rows for whatever reason, the expected result becomes ambiguous.
// First select everything in the requested range ordered by time.
$sql = "SELECT `time`, B3_4_5 FROM your_table WHERE `time` BETWEEN ? AND ? ORDER BY `time`";
$stmt = $pdo->prepare($sql);
$stmt->execute([$query_start, $query_end]);
// Initialize two DateTime objects (start and end) used to calculate the total time.
$total_start = new DateTime('00:00');
$total_end = clone $total_start;
$off = null;
while ($row = $stmt->fetchObject()) {
if ($row->B3_4_5) {
$on = new DateTime($row->time);
// increment total end time with difference between current off/on times
if ($off) {
$total_end->add($on->diff($off));
}
} else {
$off = new DateTime($row->time);
}
}
// total downtime is difference between start and end DateTimes
$total_downtime = $total_start->diff($total_end);
$total_downtime is a DateInterval object. You can get return a message using its format method:
echo $total_downtime->format('Total downtime: %h hours, %i minutes, %s seconds.');
This is the basic idea... It selects the result into a single row andcolumn, which you can then fetch withPHP`...
This solution assumes that stops & starts come in pairs, i.e: the ID of a start will be +1 that of a stop. Otherwise you should SELECT/JOIN the ID that is > that of the stopped one, and LIMIT it to 1.
A self join might not yield optimal performance wise, so be careful and measure execution times with some data to be on the safe side.
http://sqlfiddle.com/#!9/de72bf/1
CREATE TABLE fillercdown (
`fillercdown_ndx` int(11) NOT NULL AUTO_INCREMENT,
`time` datetime DEFAULT NULL,
`B3_4_5` int(11) DEFAULT NULL,
PRIMARY KEY (`fillercdown_ndx`),
KEY `fillercdowntimendx` (`time`)
) ENGINE=InnoDB AUTO_INCREMENT=0 DEFAULT CHARSET=latin1;
INSERT INTO fillercdown
(`time`, `B3_4_5`)
VALUES
('2016-06-16 14:00:45', 0),
('2016-06-16 14:01:00', 1),
('2016-06-16 16:00:00', 0),
('2016-06-16 16:01:00', 1)
;
SELECT SUM(TIMEDIFF(g.`time`, f.`time`))
FROM fillercdown f
INNER JOIN fillercdown g
ON g.`fillercdown_ndx` = (f.`fillercdown_ndx` + 1)
AND g.`B3_4_5` = 1
AND TIME(g.`time`) BETWEEN '08:00:00' AND '17:00:00'
WHERE f.`B3_4_5` = 0
AND TIME(f.`time`) BETWEEN '08:00:00' AND '17:00:00'
If you want to include times where the machine stopped but has not yet restarted, you can do something like this:
http://sqlfiddle.com/#!9/d113b9/9
INSERT INTO fillercdown
(`time`, `B3_4_5`)
VALUES
('2016-06-16 14:00:45', 0),
('2016-06-16 14:01:00', 1),
('2016-06-16 16:00:00', 0),
('2016-06-16 16:01:00', 1),
('2016-06-16 16:02:00', 0)
;
SELECT SUM(TIMEDIFF(COALESCE(g.`time`, '2016-06-16 16:02:01'), f.`time`))
FROM fillercdown f
LEFT JOIN fillercdown g
ON g.`fillercdown_ndx` = (f.`fillercdown_ndx` + 1)
AND g.`B3_4_5` = 1
AND TIME(g.`time`) BETWEEN '08:00:00' AND '17:00:00'
WHERE TIME(f.`time`) BETWEEN '08:00:00' AND '17:00:00' AND f.`B3_4_5` = 0
You could replace 2016-06-16 16:02:01 with NOW() or something based on f.time, it depends on your application needs of course.
If you never want to get NULL but rather 0, if there are no matching rows, then do something like: COALESCE(SUM(...), 0).
If you prefer a scripted solution you can always do something like this:
SELECT f.`time`, f.`B3_4_5`
FROM fillercdown f
WHERE TIME(f.`time`) BETWEEN '08:00:00' AND '17:00:00'
And then compute the sum, like so (psuedocode):
stopped = null;
pairs = []
for ( row in rows )
if ( row.isStopped ) stopped = row
else
pairs += [stopped, row]
stopped = null
sum = 0
for ( pair in pairs )
sum += duration( pair[0], pair[1] )

MySQL procedures - incrementally recalculate rows

I have a quite trivial task of calculating budget entries (income/outcome/balance). There can be thousands of entries and I can change any of them in the middle. As the result, all later entries balance must be recalculated.
Right now I am doing it in PHP by iterating through array of all entries, and updating rows that changed. It takes too much time that way - my server stops responding for several minutes.
I suppose that it happens because PHP calls MySQL for every entry update, though for PHP itself this task of array iteration and recalculation is pretty cheap. I think that there must be a way to throw this task at MySQL, so it does the iteration/recalculation/update itself, which might be cheap as well.
I am not an expert in MySQL at all, but I heard that there are stored procedures that might be the cure.
Here is my MySQL (5.5.33) table:
CREATE TABLE `entry` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`date` date DEFAULT NULL,
`is_income` tinyint(1) NOT NULL DEFAULT '0',
`income` decimal(20,2) DEFAULT NULL,
`outcome` decimal(20,2) DEFAULT NULL,
`balance` decimal(20,2) DEFAULT NULL,
PRIMARY KEY (`id`)
)
Here is my PHP (5.3.27):
//...
//$DB is a class for operating DB
$entries = $DB->get_all('entry'); //retrieves all entries from 'entry' table, sorted by date
$balance = 0;
foreach ($entries as $e) {
if ($e['is_income']) {
$balance += $e['income'];
} else {
$balance -= $e['outcome'];
}
if ($balance <> $e['balance']) {
$e1 = $e;
$e1['balance'] = $balance;
$DB->update('entry', $e1); //update the row by doing query('UPDATE `entry` ... WHERE id=' . $entry_id);
}
}
Can you point me the right direction? Thanks!
I think you can do this in a single SQL UPDATE query, no procedure needed.
UPDATE entry AS e1
JOIN (SELECT * FROM entry ORDER BY date) AS e2 ON e1.id = e2.id
CROSS JOIN (SELECT #balance := 0) AS var
SET e1.balance = (#balance := #balance + IF(e2.is_income, e2.income, -e2.outcome))
The user variable #balance serves the same purpose as the PHP variable $balance. The subquery is needed because MySQL doesn't allow use of ORDER BY in a multi-table UPDATE query, so you need to join with a subquery that produces the IDs in date order.
The "proper" way is to do the summation when displaying the report, and not store it in the table.
For only "thousands", it should not be a performance problem.

Count number of logins per day in PHP Timeclock (PHP Mysql)

What are the mysql codes to count the number of logins per day in PHP Timeclock?
timestamp bigint(14) is used and I have no idea how to separate them by date.
How do I count the number of ROWS per day?
Here's the command to create the table info:
CREATE TABLE info (
fullname varchar(50) NOT NULL default '',
`inout` varchar(50) NOT NULL default '',
timestamp bigint(14) default NULL,
KEY fullname (fullname)
) ENGINE=MyISAM;
Sorry I'm just a newbie trying to understand php and MySQL.
Anyway, I can add either of the two in info table:
timestamp timestamp default NULL,
or logindate date default NULL,
Suppose I have this portion of the code saved in a php file, how can I modify it so date or timestamp is inserted in info table everytime a user logs in?
$time = time();
$hour = gmdate('H',$time);
$min = gmdate('i',$time);
$sec = gmdate('s',$time);
$month = gmdate('m',$time);
$day = gmdate('d',$time);
$year = gmdate('Y',$time);
$tz_stamp = mktime ($hour, $min, $sec, $month, $day, $year);
if (strtolower($ip_logging) == "yes") {
$query = "insert into ".$db_prefix."info (fullname, `inout`, timestamp, notes, ipaddress) values ('".$fullname."', '".$inout."',
'".$tz_stamp."', '".$notes."', '".$connecting_ip."')";
} else {
$query = "insert into ".$db_prefix."info (fullname, `inout`, timestamp, notes) values ('".$fullname."', '".$inout."', '".$tz_stamp."',
'".$notes."')";
}
$result = mysql_query($query);
Since it's a BIGINT (why, btw?) I assume it's a UNIX Timestamp.
I haven't tested this, but something along the lines of this should work:
SELECT DATE(FROM_UNIXTIME(timestamp)) AS date, COUNT(*)
FROM info
GROUP BY date
You might wanna just store the timestamp as a TIMESTAMP column type, and then just use DATE(timestamp) to group by date.
Add a column of date only (without the time) and use this:
SELECT COUNT(*), dateColumn FROM info WHERE fullname='{The user full name}' GROUP BY dateColumn

Timestamp comparison to delete when mysql timestamp > 20 minutes

I want to do something which is not complicated but I do not manage to succeed even after I tried a lot of things....
First of all, I have a database mysql with a row of timestamp type. I insert into it elements with a date like this:
$date = date('Y-m-d H:i:s', time());
$req =mysql_query("INSERT INTO my_table (id, departement, voie, date,message)
VALUES ('', '$departement_token', '$voie_token','$date' , '$message_token')");
The result of this code line is a date element like this : 2012-07-19 20:18:17
I want to delete all elements with a date > current date + 20 minutes and I do not succeed...
I tried this:
mysql_query("DELETE FROM my_table WHERE DATE_SUB(date,INTERVAL 20 MINUTE) ORDER BY date");
And this:
$req=mysql_query("DELETE FROM my_table WHERE date >= TIMESTAMPADD(MINUTE,-20,NOW())
ORDER BY date");
And this:
$timePlus20min = time() + 1200;
//et on compare les deux dates
$req = mysql_query(
"DELETE FROM my_table WHERE UNIX_TIMESTAMP(date) >= '$timePlus20min' ORDER BY date");
But none of this works. Could you help me please, I think it's not too difficult but I'm out of ideas...
$period=date('Y-m-d H:i:s',time()-(60*60*6)); // 6 hour before
"SELECT * FROM limitlessisa WHERE UNIX_TIMESTAMP(REG) > UNIX_TIMESTAMP('$period')";
REG // timestamp row name
This is working. 6 hours before listing data
In all your queries you forgot the WHERE keyword so they are syntactically wrong. Also, the ORDER BY statement has no effect as you are not executing a SELECT query. There is no result that could be ordered. Instead, a single table DELETE query returns a count of the number of deleted rows.
DELETE FROM my_table WHERE date >= DATE_ADD(NOW(), INTERVAL 20 MINUTE);
As I do not know your table structure, I tried this query with the following table:
CREATE TABLE `datetest` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`date` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci AUTO_INCREMENT=3 ;
try this :
$req=mysql_query("DELETE FROM my_table WHERE date <= ".date("Y-m-d H:i:s", mktime(date("H"), date("i")-20, date("s"), date("m"), date("d"), date("Y")));
Bonne chance Ć  toi / Good luck
Try this:
DELETE FROM my_table WHERE UNIX_TIMESTAMP(date) > 60 * 60 * 20 + UNIX_TIMESTAMP();

Categories