Daily cron to poll mysql and update status based on timestamp - php

I have a db full of email users that lists the date and time they signed up in a column called signup_date using the DATETIME type (it uses now() ) and I also have an expire_date column which lists the same format but exactly a year later using ADDDATE(NOW(), INTERVAL 365 DAY)
I have added a status column with values being either 0 or 1. I guess this can be an ENUM type. Upon registration, status is set to 1 for active.
What I want is that if the timestamp of the expire_date is older than the current time, the cron should execute an update on that row of the user setting the status to 0. In postfix, I altered the query and appended the status=1 so that it will select the user with only status of 1. If the status isn't 1, then the user will not be found and won't be able to log in. This cron can run daily. I'm not too anal about having it run every second. Users can renew their emails within the next day. So this is my simple way of expiring emails, if they are not active or so after a year. What I need help with is constructing the cron. Should this be done with just php or does some bash need to be used? Im unclear of how to structure the script. Thanks.

Why maintain an additional flag column? You can calculate the status on the fly
SELECT *
FROM table_name
WHERE expire_date > NOW()
This will return only unexpired rows
If you need status to be produced as a column you can do
SELECT *, (expire_date > NOW()) status
FROM table_name

Related

MySQL select where timenow > database time

I have a PHP script which creates a new order and inserts the time NOW + 15 minutes into the database.
After 15 minutes have expired the user cannot access the order page.
On the admin panel I only want to show records that have not expired, so my question is what select statement would I use to do this, and which would be the most efficent?
SELECT * FROM `orders` WHERE datenow > date
The "date" is the date of the order + 15 minutes
P.S.
Aternativly, is there any way to do this using PHP so I don't have to put too much stress on the database?
Many Thanks!
Given that you want records that have not yet expired, you want all records where date is greater than NOW().
SELECT
*
FROM
`orders`
WHERE
`date` > NOW()
As the comments mentioned, it is usually better to handle this on the database side; rather than transfer (assuming you have split database and web servers) the entire data set to filter it in the application code.
The other benefit of having all the datetime functions be on the same server (in the database in this case), is that especially on some shared hosting environments, the timezone for the database cannot be changed. Therefore, you want the time comparisons to occur in the same timezone.

Automatically update data in sql for a webpage

So I'm a software Development student and for my web class I created a project that uses among other things Php and SQL; In this project, users can create posts and other users can comment on them.
The thing is I want posts to only be available for a certain period of time.
Then I have an SQL table named 'Posts' and they have a column named 'Status' (you know, if the status it's 0 they're not available and else they are.)
When a user creates a post I make SQL:
INSERT INTO posts *All the post data*, I set the Status to 1 and make a TIMESTAMP to register the date of creation of the post. I want that a week after the date registered in the Timestamp changes the status column to 0 but I don't want it to be with a page request (I need it to be automatic) and I want the user to be notified via email or something.
Can it be made with some python CGI that checks the date, updates the Status and sends the email or is there a better/easier way to do it?
Thanks a lot for your help :)
You dont need the status 0/1 AND the timestamp column, if all you want to do is show a post for a set period of time.
Just use the timestamp column and amend the queries that fetch the posts to only show those posts that are < 7 days old (or any period you decide)
EG
SELECT * from posts where timestamp_col < DATE_SUB(NOW(), INTERVAL 7 DAY)
or something similiar that meets your needs
Turns out the best way to solve this was using Cron Jobs.
I run a PHP script every day and I modify the posts which are exactly 7 days old, using
UPDATE Posts SET Status = 0 WHERE DATE(timestamp_col) = DATE_SUB(NOW(), INTERVAL 7 DAY)
And then I iterate through the affected rows emailing the users.

Count active users per hour based on two datetime entries

I have a MySQL query question.
In my web app I record the active listeners on my Shoutcast server in a MySQL database table, which includes "created", a datetime field for when they tuned in, and an "updated", a datetime field for the latest time the server polled the Shoutcast server (each minute). Plus, I also retrieve the duration in seconds of there listening session, plus the uid (aka session id) which is unique to each session.
What I would like to do is count the amount of listeners per hour, for example 13:00 = 20 listeners, but I would like to include not only those who are tuned in, so "created" datetime field, but also any listeners who where still listening from the previous hour, so the "update" datetime field.
What query would I need to achieve this. I would only generate 1 days worth of results at a time.
I understand how it would use something similar to "COUNT(id) AS hits" and "GROUP BY", but I'm not sure how to factor in the datetime fields, as the "update" datetime field is constantly updated, as long as the user is still listening. And some users can remain listening for 3 hours+.
Edit
The the main parts of the database schema is: id (int 20), created (datetime), updated (datetime), uid (int 20), duration (int 10).
The desired result would look something similar to:
(Time / hits) 0900 => 10, 1000 => 15, 1100 => 5, 1200 => 8, 1300 => 25
and so on...
This is a query I've used to filter results by country, which uses group by and count():-
SELECT country, COUNT(id) AS hits FROM listeners_log WHERE YEAR(created) = YEAR(NOW()) AND MONTH(created) = MONTH(NOW()) AND duration >= 60
The query also has an added filter on the end, to filter out session that are less than 60 seconds long.
To elaborate a little more, the created field reflects when a user connects/starts a listening session. For example, they tune in at 2016-03-21 15:00:00 that is reflected in the created field. But if they're still listening in 1 hour's time, the update field will read 2016-03-21 16:00:00, but the created field will remain the same.
Update:
I've come up with the following SQL, but this only counts the inital connection, indicated by the created field, and ignores if a use remains connected from one hour to a next.
SELECT HOUR(created), COUNT(id) AS hits FROM listeners_log WHERE DATE(created) = CURDATE() group by HOUR(created)
So you will be only needing to query on 'update' datetime field, because even if a new user comes its entry gets created with 'created' datetime as well as in next update under 'update' datetime, so now your concern will be only to query on 'update' datetime for any particular hour.
SELECT COUNT(id) FROM TABLE_NAME
WHERE update_Field BETWEEN DATE(NOW() - INTERVAL 1 HOUR);
This is a sample query to help you out, I don't have schema now to test it.
Modify it in your way and
Let me know if it doesn't work.

MySQL event scheduler refresh error PHP

I have this code in my php, but everytime I refresh the page it says Event 'expired' already exist. any way that it would not pop up anymore?
$auto = mysql_query("CREATE EVENT expired ON SCHEDULE EVERY 1 MINUTE DO UPDATE stocks SET status='expired' WHERE expdate < NOW() ") or die (mysql_error());
Thanks
By the looks of it, every time you refresh the page it will attempt to create a new event with the name expired.
If you only want to create one event and never worry about it again (and based on that query, it looks like you do), you should just do it once in the database directly.
However, if you really want to keep it in your code, you could use IF NOT EXISTS: https://dev.mysql.com/doc/refman/5.1/en/create-event.html
CREATE EVENT IF NOT EXISTS expired ON SCHEDULE EVERY 1 MINUTE DO UPDATE stocks SET status='expired' WHERE expdate < NOW()
However, if all you want to do is determine the state of a stock at a give time, it might make more sense to use MySQL's IF logic to derive a status at any point (and not actually have a status field in your table): https://dev.mysql.com/doc/refman/5.0/en/control-flow-functions.html#function_if
SELECT *, IF(expdate < NOW(), "expired", IF(expdate < NOW() + INTERVAL 10 DAYS), "critical", "fine")) AS status FROM stocks

Change record automatically

On the website i'm developing i'm making a system for ban and unban users.
In my database i have a table 'banned' with fields about the bans (userID, active, date was made, reason ecc).
What i want to do is:
Add another field for expire date, and when this date occur, change automatically the field 'active' to 0.
How i can do that?
I would not use two fields like you did -- because I would not want to depend on a task to change back the active field when the un-ban date is reached.
Instead, I would only use one datetime field, called like banned_until; and this field would either:
Be NULL when the user is not banned,
Or contain the date until which the user is banned.
Then, when the user tries to do something (log-in, post, ...), I would check that :
This field is NULL, in which case the user is not banned
Or that the date contained in this field is in the past, in which can the user has been banned, but is no longer.
In the second case, you could even reset the field to NULL, as the un-ban date has been reached.
Its either you use a cron script or when getting banned users, you apply a where clause to check if the the ban has expired
Create a php script that will check if time is passed the expiration date. SQL will be something like this:
UPDATE banned SET active=0 WHERE expire_date<=NOW()
Save it as a for example task.php
Then create a cron task with crontab -e
*/10 * * * * php /path/to/your/taks/task.php
And this will cause this script to be executed every 10min and unban all banned ppl.
--
There are other ways, perhaps better ones, like e.g. Pascal described, but this answer is for your idea.
You can compare expiry_date value with current_date to check if a user is active or not on his login.
SELECT
( DATE_FORMAT( expiry_date_field, '%Y-%m-%d' )
<
DATE_FORMAT( CURRENT_DATE, '%Y-%m-%d' )
) AS isActive
FROM
banned
WHERE
user_id=?;
A 0 returned represents in-active status and 1 as active.
But irrespective of a user's login, if you want to maintain active status of users, you can achieve this using the Event Scheduler.
Following example gives you an idea in implementing one.
drop event if exists event_user_bans_scheduling;
delimiter //
create event if not exists event_user_bans_scheduling
-- on schedule every 86400 second starts 00:00:00
-- at timestamp( adddate( current_date, 1 ),'00:00:00' )
on schedule every 1 day starts timestamp( current_date + 1, '00:00:01' )
comment 'Scheduler to update active status of users'
do
UPDATE my_app_db.banned
SET ACTIVE=0
WHERE
date_format( expiry_date_field,'%Y-%m-%d' ) = date_format( CURRENT_DATE, '%Y-%m-%d' );
;
//
delimiter ;
Note:
The global event_scheduler system variable determines whether the Event Scheduler is enabled and running on the server. Read complete notes on Event Scheduler Configuration before working on MySQL events.

Categories