I have a SQLite3 DB with entries storing sensor readings. Each row in the table looks like this:
time | temp1 | humid1 | temp2 | humid2
2013-12-07 23:15:51 | 26.06 | 16.29 | 22.24 | 17.55
where the first entry is the date, and the following ones are sensor data.
Now what I need to do is, using PHP, get the most recent 30 minutes of readings. I only want data that's less than 30 minutes old, since it's possible that data collection wasn't running and I would then get old data if I just selected the first bunch of values.
I can think of 2 ways I could do this:
Is there some way in SQLite to do something like this?
SELECT * FROM table WHERE time < (time-30 minutes)
The other thing I could do is grab the first 300 values (equivalent to 30 minutes)
and then compare the year, month, day, hour, and minute myself. The problem is, I don't know how to extract those from the PHP variable I get when I do just
SELECT * FROM table ORDER BY time DESC limit 300
So let's say I get a row (in PHP) called $row, where the time is $row['time'].
How would I go about extracting the years, months... etc. from that and comparing it to the current time?
You should be able to do something like this:
SELECT * FROM table WHERE time > datetime('now', '-30 minutes');
Related
I'm writing a script using PHP & MySQL where I can record the shifts I work (HGV driver).
Upon posting the form data PHP calculates shift duration, wages accumulated, overtime, distance driven, etc, and stores it in the MySQL database.
I want to then display all shifts in a table but group them by my pay week which unfortunately starts on a Sunday.
If the pay week was Mon-Sun I wouldn't have this problem as I could use week numbers but I can't due to the week starting on a Sunday.
My code is as follows:
^^^^^^^^^^^^^^^^^^^
// DB Connection //
// Return the earliest shift in the database //
$result = $db->query("SELECT * FROM `shifts` ORDER BY `shift_start` ASC LIMIT 1");
$data = $result->fetch_assoc();
// Establish the previous Sunday //
$week_from = strtotime(date('Y-m-d',mktime(0,0,0,date('m',$data['shift_start']),date('d',$data['shift_start']),date('y',$data['shift_start']))) . 'last sunday');
// PHP Loop Goes Here //
Firstly, is the above code the most efficient way of getting the start date (previous Sunday)?
Secondly, what's the best way to loop through the weeks where there are shifts?
TIA
This is a two part question, so I will try to cover them separately.
Regarding your first question, I would suggest using the MIN() function when selecting the smallest or earliest value in a database, and ensuring you have an index on the "shift_start" column. More information on the difference between MIN() and ORDER BY/LIMIT can be found here.
Then your query would look a something like this:
SELECT MIN(`shift_start`) FROM `shifts`;
Personally, I also find MIN() far more readable.
Now, for the other (and far more complicated) question:
You've not provided much detail on what your database (or the contents) looks like. Since you're using the PHP date function, I am assuming you're saving the timestamps as UNIX instead of MySQL TIMESTAMP/DATETIME types.
Firstly, I would suggest you migrate to using a TIMESTAMP/DATETIME column type. It'll simplify the query you're attempting to run.
If you're unable to change to a TIMESTAMP/DATETIME column, then you can convert a UNIX timestamp to a DATETIME.
MySQL has a YEARWEEK() function that you can use to group by:
SELECT STR_TO_DATE(CONCAT(YEARWEEK(`shift_start`), ' Monday'), '%X%V %W') AS `date`, SUM(`wage`) AS `wage` FROM `shifts` GROUP BY YEARWEEK(`shift_start`);
This will output something similar to:
+------------+------+
| Date | Wage |
+------------+------+
| 2021-11-29 | 50 |
| 2021-12-06 | 15 |
+------------+------+
I am trying to delete a row from my table after 12 hours have passed from the row being created.
I have a dateTime column in my table which records the time at which it was created, is there a way to delete a row after 12 hours dynamically? Another problem this creates is that the date may change during the 12 hours, which may render the timestamp of the row irrelevant.
I have tried to do some simple SQL Queries from examples I have found on similar questions although I do not know how to deal with the date-change aspect of the problem.
Example Queries:
DELETE FROM detail1 WHERE date < DATETIME('NOW', '-1 hours');
Here is my table:
ID |Position| dateApplied
1 | 1 | 2019-07-20 05:23:16
2 | 2 | 2017-07-20 12:13:30
I would like to find a query to help me delete each row after 12 hours.
You should create a script and call it periodically with Cron Jobs, In that script check all the rows and delete expired ones.
It's easier if you save "expiry time" in the tabale:
$expireAfter = time() + (12 * 60 * 60); // time returns number of seconds since the Unix Epoch
Then in the periodic script, you can check if the row is expired or not:
$now = time();
$queryString = "DELETE FROM detail1 WHERE `expiry_time` < $now;";
With this approach, you don't need to worry about changing the date.
I have a structural MySQL question about storing events in a database with dates.
Say that an organiser would select a range of dates, eg:
["19/12/2014","20/12/2014","26/12/2014","27/12/2014","02/01/2015","03/01/2015","09/01/2015","10/01/2015"]
The event needs to be saved into a table, I'm thinking about creating a many-to-many table with the structure:
event_id | start_date | end_date
Now when thinking about it, this would mean that I'd need to convert the date array into an array of object with beginning - end date.
Now the alternative would be to just create a table that looks like this:
event_id | event_date
And create a separate record for every date.
The purpose is obviously to check which events should be sent back to the client within a given date range.
Which of the two options seems to common / viable?
It is pretty crucial for the setup.
Depends. If the first event ends on the date of the second event, you can go with event_id | event_date, but otherwise I'd go with the first option.
If you don't have the end date somehow, then how will you be able to tell the client the range of dates for the event?
I would go with setup that contains event duration (in seconds) - it's flexible.
event_id (int) | start_date (datetime) | duration (int)
In this case when event duration does not matter - put 0 there in other case just put the number o seconds so you will be able to store event which lasts days or just a few hours or minutes.
I'm querying a postgresql database which holds an agenda-table:
agenda |> id (int) | start (timestamp) | end (timestamp) | facname | .....
I want to make a kind of summary of one day in the form of a 'timeline' consisting of a small picture for every 15 minutes interval: on / off according to the availability of the facility.
Now is it relatively simple to query the database for every 15 minutes and check if a reservation is present and change the img source.
But if you want to make an overview of 10 days and 5 different facilities you'll end up querying the database
10(days) * 36(quaters a day) * 5 (facilities) = 1800 database querys/page load.
So this results in a very heavy pay load.
Is there a way I can reduce the amount of queries and so the payload?
To solve this issue, I think we may first find a way to, given a timestamp, find in which quarter of an hour it belongs to. For instance, the hour 08:38 belongs to quarter 08:30, the 08:51 to 08:45, and so on.
To do that, we can use a function like this:
CREATE FUNCTION date_trunc_quarter(timestamp )
RETURNS TIMESTAMP
LANGUAGE SQL
IMMUTABLE
AS $$
SELECT * FROM
generate_series(
date_trunc('hour',$1),
date_trunc('hour',$1)+interval '1hour',
interval '15min'
) AS gen(quarter)
WHERE gen.quarter < $1
ORDER BY gen.quarter
DESC LIMIT 1
$$;
It uses the generate_series function to generate all the four quarters (e.g. 08:00, 08:15, 08:30 and 08:45) within the same hour as the given timestamp (e.g. 08:38), do get the given hour it uses the well-known date_trunc function. Then, it filters only the quarters which is smaller then the given timestamp, sort it and get the bigger one. As it is always only four values at most, sorting it is not a big issue.
Now, with that you can easily query like this:
SELECT date_trunc_quarter(tstart) AS quarter, count(*)
FROM agenda
GROUP BY quarter
ORDER BY quarter;
I think it is fast enough, and to make it even faster, you can create an expression index on agenda:
CREATE INDEX idx_agenda_quarter ON agenda ((date_trunc_quarter(tstart)));
See this fiddle with a self-contained test case of it all.
I'm working on a web application written on php. I have some objects (represented as rows) in mysql table. And I need to show them randomly during a day.
How can I limit the show count of a particular object, e.g not more than 10 times for an hour?
By the show count I mean how many times the object was rendered.
For example, there are 100 images and with each pageview random 5 are shown. I need to normalize the image shows distribution, by limiting images' show count for an hour, for preventing 1000 shows for one image and 3 to another.
Hope its useful explanation.
Probably the simplest way to do it would be to add a field called last_shown to your table and then exclude it from the candidate list if it's been shown within the hour. eg something along these lines:
SELECT id FROM my_objects WHERE last_shown < DATE_SUB(NOW(), INTERVAL 1 HOUR) ORDER BY RAND() LIMIT 1
Then when you display that actual object, timestamp the column, ie:
UPDATE my_objects SET last_shown = NOW() WHERE id = <the_id_you_displayed>
This approach is simpler, but just as effective. If you reduced the timeframe to once every 6 minutes, it would effectively be similar logic to '10 times within the hour', and not require an entire new reference table.
You could create a log table with id and date_displayed.
Each time you select the rows random, you make sure that you select only rows which were not displayed more than 10 times in the last hour.
SELECT * FROM table
WHERE id NOT IN (
SELECT id FROM log
WHERE date_displayed > now() - interval 1 hour
GROUP BY id HAVING COUNT(*) >= 10
)
ORDER BY rand()
Also, after one hour you no longer need older inserts, so you might want to do a DELETE query to remove old records.
DELETE FROM log WHERE date_displayed < now() - interval 1 hour