I have a cron that runs some php with some mysql just after midnight everyday. I want to take all registered users (to my website) and send them a reminder and copy of the newsletter. However I want to do this every 30 days from their registration.
I have thought as far as this:
SELECT * FROM users
WHERE DATE(DT_stamp) = DATE(NOW() - INTERVAL 30 DAY
But this will only work for 30 days after they have registered, not 60 and 90.
Effectively I want:
Where days since registration is divisible by 30
That way every 30 days that user will get picked up in the sql.
Can someone help me formulate this WHERE clause, I am struggling with mysql where day(date1-date2) divisible 30
The DATEDIFF function returns the difference between two dates in days, ignoring the time:
SELECT * FROM users
WHERE DATEDIFF(DT_stamp, NOW()) % 30 = 0
or the other way round...
SELECT * FROM users WHERE MOD(DATEDIFF(NOW(),registration_date),30) = 0;
Use SQL modulo function MOD():
SELECT * FROM users
WHERE MOD( DATE(DT_stamp) - DATE(NOW()), 30) = 0
In mysql, you can also use the % operator, which does the same thing:
SELECT * FROM users
WHERE (DATE(DT_stamp) - DATE(NOW()) % 30 = 0
Just an addition (not that nine years had passed :)
If you want to skip today's date you should add
AND DATEDIFF(NOW(), DT_stamp) != 0;
making it
SELECT * FROM users WHERE MOD(DATEDIFF(NOW(), DT_stamp), 30) = 0 AND DATEDIFF(NOW(), DT_stamp) != 0;
Related
I have a table that contains sensor data with a column timestamp that holds the unix timestamp of the time the sensor measurement has been taken.
Now I would like to SELECT all measurements within a certain date/time range with a specific time step.
I figured the first part out myself like you can see in my posted code snippet below.
// With $date_start and $date_stop in the format: '2010-10-01 12:00:00'
$result = mysqli_query($connection, "SELECT sensor_1
FROM sensor_table
WHERE timestamp >= UNIX_TIMESTAMP($date_start)
AND timestamp < UNIX_TIMESTAMP($date_stop)
ORDER BY timestamp");
Now is there a convenient way in MySQL to include a time step size into the same SELECT query?
My table contains thousands of measurements over months with one measurement taken every 5 seconds.
Now let's say I would like to SELECT measurements in between 2010-10-01 12:00:00 and 2010-10-02 12:00:00 but in this date/time range only SELECT one measurement every 10 minutes? (as my table contains measurements taken every 5 seconds).
Any smart ideas how to solve this in a single query?
(also other ideas are very welcome :))
Since you take one measurement every 5 seconds, the difference between $date_start and the first matching measurement cannot be greater than 4. We then take one entry every 600 seconds (allowing for some discrepancy from clock to clock...)
SELECT sensor_1
FROM sensor_table
WHERE timestamp >= UNIX_TIMESTAMP($date_start)
AND
timestamp < UNIX_TIMESTAMP($date_stop)
AND
((timestamp - UNIX_TIMESTAMP($date_start)) % 600) BETWEEN 0 AND 4
ORDER BY timestamp;
It is not elegant, but you can do:
SELECT s.sensor_1
FROM sensor_table s
WHERE s.timestamp >= UNIX_TIMESTAMP($date_start) AND
s.timestamp < UNIX_TIMESTAMP($date_stop) AND
s.timestamp = (SELECT MIN(s2.timestamp)
FROM sensor_table s2
WHERE s2.timestamp >= 60 * 10 * FLOOR(UNIX_TIMESTAMP(s.timestamp) / (60 * 10)) AND
s2.timestamp < s2.timestamp >= 60 * 10 * (1 + FLOOR(UNIX_TIMESTAMP(s.timestamp) / (60 * 10)))
)
ORDER BY timestamp;
This selects the first in each 10 minute period.
I think that you could use a simple cursor in plSQL
CREATE TABLE StoreValuesId
(
valueId int primary key;
)
CREATE OR REPLACE procedure_store[date_start date,date_stop date]
DECLARE date_startUpdated date , date_stopUpdated date , date_diff TIME(7) = '00:10:00'
IS
BEGIN
SELECT date_start INTO date_startUpdated;
SELECT date_stop INTO date_stopUpdated;
IF timestamp BETWEEN date_start and date_stop then
INSERT INTO StoreValuesId values(timestamp)
date_startUpdated=DATEADD(SECOND, DATEDIFF(SECOND, 0, date_diff), date_startUpdated);
date_stopUpdated=DATEADD(SECOND, DATEDIFF(SECOND, 0, date_diff), date_stopUpdated);
END IF
COMMIT;
END
Then again the syntax might be wrong but I hope you'll get the idea (haven't played with sql in a while)
In this query which I got help from #jarlh, in this question ORDER BY CASE
SELECT *
FROM booking
WHERE booking_date=$b_date OR DATE(delivery_date)=$b_date
ORDER BY CASE WHEN booking_date=$b_date
THEN hour * 60 + minute
WHEN DATE(delivery_date)=$b_date
THEN HOUR(delivery_date) * 60 + MINUTE(delivery_date)
END ASC
I need to find those posts with the same HOUR and MINUTE, before I leave the query, and mark them somehow, so I’m able to print them (those in the same hour and minute) horizontally and not vertically.
I am trying to create a SELECT statement from two different tables, where I use to send messages, I don't want to send a message to someone for 1 wk after they join, however if I have already sent them a message I want to wait 10 days before sending next one.
Here's what I have:
SELECT c.*, g.resToMeeting, g.replied, g.conlevel, g.coffee, g.lastMessageSent
FROM connections c
INNER JOIN groupmembers g
ON c.Id=g.Id
AND g.groupN=244 # this decides the client I'm pulling for...(or group they own)
AND g.client=c.client
AND g.conlevel=1
AND (datediff(curdate(), g.lastMessageSent) > 10 OR datediff(curdate(), c.dateConnected) > 7)
AND c.validated=1
AND c.process_rank=0
ORDER BY c.dateAdded ASC
LIMIT 0, 200
The trouble I'm having is that it shows EITHER people who haven't joined within the last week, OR people who haven't received a messages within the last 10 days. It seems that it isn't working:
I received a record that had lastMessageSent as 2015-04-29, (which isn't 10 days ago) but the dateConnected was 2015-04-15 which was over 7 days. How can I enforce both rules "together" not either or, sometimes there is no data in lastMessageSent or dateConnected, and that should be OK.
Generally speaking, the ON clause should say how the tables are connected.
After that, you have a WHERE clause that lists whatever filtering you need for any of the tables.
I suspect you should have had:
... INNER JOIN groupmembers g
ON c.Id=g.Id
WHERE g.groupN=244 ...
Edit
I think you want this, not XOR:
AND g.lastMessageSent < NOW() - INTERVAL 10 DAY -- Avoid frequent spamming
AND c.dateConnected < NOW() - INTERVAL 7 DAY -- Wait a while before first message
Note that I reforumlated the comparisions -- it is always good to have the column on one side and a constant on the other. This allows for the possibility of using an INDEX; hiding the column inside DATEDIFF() does not.
CURDATE counts back from midnight this morning; NOW counts back from this second. (You pick; I am merely suggesting an alternative.)
Caution: If "no message ever sent" is stored as NULL in g.lastMessageSent, then the above will be false. So perhaps you need
AND ( g.lastMessageSent IS NULL
OR g.lastMessageSent < CURDATE() - INTERVAL 10 DAY ) -- Avoid frequent spamming
AND c.dateConnected < CURDATE() - INTERVAL 7 DAY -- Wait a while before first message
"Either..or", in my understanding, is OR. "Either, but not both" is XOR.
Why can you just change:
AND (datediff(curdate(), g.lastMessageSent) > 10 OR datediff(curdate(), c.dateConnected) > 7)
to:
AND datediff(curdate(), g.lastMessageSent) > 10
AND datediff(curdate(), c.dateConnected) > 7
"EITHER" is an XOR. i.e. (A and not B) or (not A and B), so change this condition
AND (datediff(curdate(), g.lastMessageSent) > 10 OR datediff(curdate(), c.dateConnected) > 7)
To
AND ( ((datediff(curdate(), g.lastMessageSent) > 10 AND datediff(curdate(), c.dateConnected) < 7)) OR ((datediff(curdate(), g.lastMessageSent) < 10 AND datediff(curdate(), c.dateConnected) > 7)) )
Note that instead of using NOT, I inverted the condition.
EDIT
Since MySQL has XOR operator, it is possible to rewrite the line as:
AND (datediff(curdate(), g.lastMessageSent) > 10 XOR datediff(curdate(), c.dateConnected) > 7)
So my script currently forces the user to send a "ping" every 10 minutes. This inserts a record into MySQL with the user ID and the current timestamp.
What I would like to achieve is seeing if any of the users went offline recently.
In theory that would be selecting a recently online (20ish minutes ago) user, then checking if there has not been a ping in the past 11 minutes except I don't seem to be able to figure out how.
This is what I have so far:
SELECT * FROM status WHERE time > (CURTIME() - 1200) AND time < (CURTIME() - 660)
I have to add, I do this in combination with PHP but that shouldn't really matter.
Any help is appreciated.
I would try something like that :
SELECT TIMEDIFF(CURTIME(), MAX(s.time)) AS duration, s.user
FROM status s
GROUP BY s.user
HAVING duration > 660 AND duration < 1200;
If the username is not stored in the status table. You should perform a JOIN between Status and User.
You can use a BETWEEN statement if you want to check duration for a specific range too.
EDIT : Thanks to Madbreaks about the "recently" constraint. You can add a AND duration < xxxx to do not retrieve old durations and keep only "recent" status in your result set.
There are a lot of ways to do this. Here's one, assuming you have a primary key called id:
SELECT *
FROM status
LEFT JOIN (
SELECT id
FROM status
WHERE time > (CURTIME() - 660) // was on within last 5 minutes
) sub ON
sub.id = status.id
WHERE
time > (CURTIME() - 1200) // was on within last 20 minutes
AND sub.id IS NULL; // was on within last 20, but not last 5
Use between for that:
SELECT *
FROM `status`
WHERE (`time` BETWEEN (CURTIME() - 660) AND (CURTIME() - 1200))
I'm making a fitness logbook where indoor rowers can log there results.
To make it interesting and motivating I'm implementing an achievement system.
I like to have an achievement that if someone rows more than 90 times within 24 weeks they get that achievement.
Does anybody have some hints in how i can implement this in MYSQL.
The mysql-table for the logbook is pretty straightforward: id, userid, date (timestamp),etc (rest is omitted because it doesn't really matter)
The jist is that the first rowdate and the last one can't exceed the 24 weeks.
I assume from your application that you want the most recent 24 weeks.
In mysql, you do this as:
select lb.userid
from logbook lb
where datediff(now(), lb.date) >= 7*24
group by userid
having count(*) >= 90
If you need it for an arbitrary 24-week period, can you modify the question?
Just do a sql query to count the number of rows a user has between now and 24 weeks ago. This is a pretty straight forward query to run.
Look at using something with datediff in mysql to get the difference between now and 24 weeks ago.
After you have a script set up to do this, set up a cron job to run either every day or every week and do some automation on this.
I think you should create a table achievers which you populate with the achievers of each day.
You can set a recurrent(daily, right before midnight) event in which you run a query like this:
delete from achievers;
insert into achievers (
select userid
from logbook
where date < currenttimestamp and date > currenttimestamp - 24weeks
group by userid
having count(*) >= 90
)
For events in mysql: http://dev.mysql.com/doc/refman/5.1/en/events-overview.html
This query will give you the list of users total activity in 24 weeks
select * from table groupby userid where `date` BETWEEN DATE_SUB( CURDATE( ) ,INTERVAL 168 DAY ) AND CURDATE( ) having count(id) >= 90