How to get date difference in days in MySql - mysql

In mysql, I have a user table with columns
ban_start_date [datetime]
ban_days [int]
Where this means that the user is banned from ban_start_date for another ban_days days more. How can I select the user table, but add a new column saying how many days left they are banned?
I know I need to check if NOW() is in between ban_start_date and ban_start_date+ban_days, and if so, get the difference. Something like that.
Thanks

Please try:
SELECT
DATEDIFF(DATE_ADD(banned_users.ban_start_date , INTERVAL banned_users.ban_days DAY), DATE(CURDATE())) AS ban_days_left
FROM
users as banned_users
WHERE
DATE_ADD(banned_users.ban_start_date , INTERVAL banned_users.ban_days DAY) > DATE(CURDATE());
Query takes only users who are banned at execution time and then adds the ban_days to the ban_start_date temporarily producing ban-enddate (DATE_ADD(banned_users.ban_start_date , INTERVAL banned_users.ban_days DAY)). After that DATEDIFF is used to count the days between ban-enndate and today's date, which in fact should result in ban_days_left.

Why not store the ban_end_date instead? If you want you can store the ban_days, but you should not need that value very often.
The nice thing (I think) about storing the bad_end_date is that people who are not banned will have that as a NULL. It is extremely easy to look up this one value and tell the user:
"You are banned until ban_end."
At the start of the day you will have check for people with non-NULL bad_end_date values where ban_end_date < now() and set those to NULL. Easy.

Related

What's the difference between the two SQL statements?

This is a question from leetcode, using the second query I got the question wrong but could not identify why
SELECT
user_id,
max(time_stamp) as "last_stamp"
from
logins
where
year(time_stamp) = '2020'
group by
user_id
and
select
user_id,
max(time_stamp) as "last_stamp"
from
logins
where
time_stamp between '2020-01-01' and '2020-12-31'
group by
user_id
The first query uses a function on every row to extract the year (an integer) and compares that to a string. (It would be preferable to use an integer instead.) Whilst this may be sub-optimal, this query would accurately locate all rows that fall into the year 2020.
The second query could fail to locate all rows that fall into 2020. Here it is important to remember that days have a 24 hour duration, and that each day starts at midnight and concludes at midnight 24 hours later. That is; a day does have a start point (midnight) and an end-point (midnight+24 hours).
However a single date used in SQL code cannot be both the start-point and the end-point of the same day, so every date in SQL represents only the start-point. Also note here, that between does NOT magically change the second given date into "the end of that day" - it simply cannot (and does not) do that.
So, when you use time_stamp between '2020-01-01' and '2020-12-31' you need to think of it as meaning "from the start of 2020-01-01 up to and including the start of 2020-12-31". Hence, this excludes the 24 hours duration of 2020-12-31.
The safest way to deal with this is to NOT use between at all, instead write just a few characters more code which will be accurate regardless of the time precision used by any date/datetime/timestamp column:
where
time_stamp >= '2020-01-01' and time_stamp <'2021-01-01'
with the second date being "the start-point of the next day"
See answer to SQL "between" not inclusive

Isolating MySql records created today

I am just learning MySql (SQL in general) and I have a question. I ran a process to populate a table with 72 records. This was done, however, I needed to run the process again and this time it populated the table again with a second record for each user for a total now of 144 records. How can I isolate the newest records created today?
A simple solution is to use current_date to figure out today's date and date() to remove the time portion of your column. Then:
where current_date = date(createdTS)
This is fine for a small dataset as yours. As general solution, you'd need a query that won't need to manipulate every row, e.g.
where createdTS >= current_date and createdTS < current_date + interval 1 day
You just have to use your createdTS column, (assuming you know what was the timestamp of both runs).
SELECT * FROM `my_table` WHERE `createdTS` > '2019-07-25 15:00:00'
You could also RANK() over and get only the newest run for each user (something like this)

Sql to get number of hours per user per day

A table 'Log' has the below columns:
SystemName
User
Datetime - it's a timestamp
Status - has the values Start or Stop.
I need to write a query which will give me :
Number of hours spent per user per day on system X.
Please see example data below:
X, Amit, 05/01/2019 08:45:00, Start
X, Amit, 05/03/2019 13:25:00, Stop
X, Dave, 05/01/2019 09:10:35, Start
X, Dave, 05/01/2019 17:35:42, Stop
Output:
Amit,05/01/2019, 15h
Amit,05/02/2019, 24h
Amit,05/03/2019, 9h
Dave,05/01/2019, 8h
My approach till now :
I was thinking I could use lead or lag to get the consecutive times in the same row. But in the case of user Amit that spans across multiple days. Also there could be a user who has started and stopped multiple times on the same day. Even if I do that how could I generate hours for the dates amidst the range. Can you please help me.
This should work. You will only get Hours spent if both Start and Stop status exists for a user in a single day.
SELECT SystemName,[user],
CONVERT(varchar, CAST(Datetime AS DATETIME), 1) Datetime,
DATEDIFF
(
HH,
MAX(CASE WHEN Ststus = 'Start' THEN [Datetime] ELSE NULL END ),
MAX(CASE WHEN Ststus = 'Stop' THEN Datetime ELSE NULL END )
)HourSpent
FROM your_table A
GROUP BY SystemName,[User],
CONVERT(varchar, CAST(Datetime AS DATETIME), 1)
Since the output consists of one row per User + Day, then you would need to JOIN the data to a calendar table of dates.
You would need a way to extract the Start and Stop timestamp pairs for a given user, join it to the calendar table, then count the number of hours on that day that are between the start and stop times. (The hour count could be use a User Defined Function.
That's pretty complex. Frankly, I would rather write a Python program to parse the data rather than doing it via SQL. It would be very simple:
Read start line
Read end line
Loop through days, outputting hours per day (quite simple in Python)
Sometimes the best hammer is a spanner. (Translation: Sometimes a different tool is better.)

WHERE clause to filter times that are under an hour

SELECT
name,
start_time,
TIME(cancelled_date) AS cancelled_time,
TIMEDIFF(start_time, TIME(cancelled_date)) AS difference
FROM
bookings
I'm trying to get from the database a list of bookings which were cancelled with less than an hour's notice. The start time and the cancellation times are both in TIME format, I know a timestamp would have made this easier. So above I've calculated the time difference between the two values and now need to add a WHERE clause to restrict it to only those records that have a difference of under 1:00:00. Obviously this isn't a number, it's a time, so a simple bit of maths won't do it.
start_time is a TIME
cancelled_date is a DATETIME but I'm converting it to TIME in the query to then calculate cancelled_time and difference.
I would be inclined to do this by adding and hour to the notice, something like this:
WHERE start_time > date_add(cancelled_date, interval 1 hour)
I can't quite tell what the right logic is from the question, because your column names don't match the description.
In this case, so a subtraction or doing the comparison are similar performance wise. But, if you had a constant instead of cancelled_date, then there is a difference. The following:
WHERE start_time < date_add(now(), interval -1 hour)
Allows the engine to use an index on start_time.
you can use having difference<time('1:00')

How to calculate hours in mysql

My problem is in brief here...
Once a user signed in i stored his login date in the users table. If the user doesn't logged in for 72 hours i need to change his status to inactive.
How can i able to find whether 72 hours is completed or not after the user logged in using My Sql.
Thanks in advance...
I'd recommend using the TIMEDIFF() function, which you can find documented here:
dev.mysql.com timediff doc.
In your case, I'd format my where clause something like this:
WHERE
TIMEDIFF(CURTIME(), LastLoginDate) > '3 0:0:0.0'
or
WHERE
TIMEDIFF(CURTIME(), LastLoginDate) > '72:0:0.0'
I haven't done this specifically, but the base concept should work for you.
Create a CRON routine to run every hour with this query:
UPDATE users
SET status = 'Inactive'
WHERE (SELECT * FROM users WHERE last_login < now() - 259200)
To answer your question more specifically, it is the where clause, when ran, that tells you all the users that haven't logged in for 72 hours.
SELECT * FROM users WHERE last_login < now() - 259200
However, there is no way to set each user to inactive at exactly 72 hours. To get more accurate than the solution provided above, run the query more often.
*Note - insert your columns names where appropriate. Query not tested. 259200 = # of seconds in 72 hours - assumes you store your timestamps seconds (Epoch)
Use DATETIME type to store dates, subtract 72 hours from NOW() using DATE_SUB() and see if the result is larger than the value stored in the database.