So I have a quiz with a count down, Each question takes 15 seconds to answer.
When the user starts a question, I save the question_id + the end_time which would be after 15 seconds from now.
The table looks like that:
quiz_attempts
________________________________________
| id | user_id | question_id | end_time |
|____|_________|_____________|__________|
| 1 | 1 | 1 | end_time |
|____|_________|_____________|__________|
Then when the page is fully loaded, I show a counter for the user which starts from 15 seconds and ends with 0. And the user has to answer the question within 15 seconds.
<span class="counter">15</span>
The issue is that the end_time would be sooner than the 15 seconds counter shown to the user.
So for example the end_time is 12:06:22 and the counter is shown to the user ends 12:06:25. And it would depend on the internet speed of the user.
So how to time both times so that the end_time ends with the front-end counter like 12:06:22 for both?
I don't want to start with the end_time from the database, As I want the page loaded 1st so that the user can start reading and answering the question within 15 seconds not less
Related
How can I make a reward system in PHP that has a timer and sets a timer for a certain amount of time after they click on it and mysql inserts a random value into the table?
I am making a project and I want users to accumulate the in-game currency as if they were using a Bitcoin faucet.
A simple way to do this would be to keep track of the users "currency" using a table that has both amounts and datetimes. The user's balance would only show the entries that have datetimes before the current time. That way, you can insert the entry right away and then it only goes live when you need it.
rowid | user_id | amount | activetime |
-------------------------------------------------------
90000 | 1 | 0.01 | 12:13:12 01-16-15 |
90001 | 1 | 0.01 | 12:13:12 02-16-15 |
On inserts you can set the active time to something like DATE_ADD(NOW(), INTERVAL 2 HOUR) so it will show up 2 hours later.
Example of adding a row:
INSERT INTO transactions
(user_id, amount, activetime)
VALUES
(1, 0.01, DATE_ADD(NOW(), INTERVAL 2 HOUR))
Example of getting current balance for a user:
SELECT SUM(amount) AS balance FROM transactions WHERE activetime <= NOW()
Also, if you want to rate limit the user, it is easy now to check if they have already clicked the button because there will be an entry greater than the current time. You could query quickly like this:
SELECT 1 FROM transactions WHERE activetime > NOW() LIMIT 1
Then in php, if num_rows() is 1, they have already clicked the button and are waiting for payment. Otherwise it will return 0.
Hopefully this helps. Let me know if you have any other questions on this topic, or if you need some clarification.
I'm trying to write a function to move an scheduled task. The schedule can not overlap with any other event. My user inputs are as follows:
schedule_id (int)
new_start_time (DATETIME)
My table structure is as follows:
Schedules
| schedule_id | start_time | end_time | task_id
| 1 | 2015-12-21 02:00:00 | 2015-12-21 04:00:00 | 1
| 2 | 2015-12-21 08:30:00 | 2015-12-21 09:30:00 | 1
| 3 | 2015-12-22 01:00:00 | 2015-12-22 02:00:00 | 2
Tasks
| task_id | name | max_duration
| 1 | do things | 2
| 2 | do stuff | 1
A user has between start_time and end_time to start a "task". The user can not begin the "task" until that window. Once that user begins the task they have whatever the max_duration for that task ID is to complete it. There is also a 15 minute window to set up for the next task. That means a user who starts a task 1 second before the end of the window still has max_duration amount of time to complete the task. Therefore the "actual window" that nothing can be scheduled in is start_time to (end_time+max_duration+15). I would like to move an event (or insert a new one) but I must check for overlaps. Essentially I must ensure:
Does the start_time from user input run into any other schedule's end_time+max_duration+15?
Does the end_time+max_duration+15 run into any other schedule's start time. end_time is simply obtained by taking the new start_time and adding the original duration (end_time = (orig_end_time-orig_start_time)+start_time
For example, the above table is valid for schedule_id's 1 and 2 because a user can start any time between 2:00 and 4:00. Assuming he starts right at the end, 3:59:59 the event will last at max until 5:59:59. Even with the cleanup window of 15 minutes this still leads to 6:14:59 and since the next schedule starts at 8:30 this is ok.
I've been wrapping my head around this for hours. I would like to do it in pure MySQL however I am considering using PHP if I really have to. Even in PHP this problem seems difficult. Sure I could grab every schedule with a start time a day or two earlier and an end time a day or two later then compare my interval but that seems very hacky.
Any ideas?
I have a table which contains shift sign in and sign out times of employees. Each record has AutoGenID, employeeID, start datetime and end datetime. Based on these data i want to find the hours of work for each employee for a given period of time such as a month.
This is not web based but a Mobile and a PC app which can run in offline mode.
The problem is that there may or may not be multiple records for a single employee with overlapping date intervals. This is because an employee can individually sigh in on multiple devices per day and all these entries are added on this centralized database table. Hence there may or may not be overlapping date intervals for a single employee.
For example lets say that user A signed in from his mobile at '2015-07-03 10:51:19' and later signed in again from his PC at '2015-07-03 12:36:14'
At the end of the day he signed off from his PC at '2015-07-03 18:12:29' and signed off his mobile at '2015-07-03 18:19:53'
And Next day he only uses his PC to sign in. So on the database i have the following records.
+----+-----------+---------------------+---------------------+
| ID | EmpID | start | End |
+----+-----------+---------------------+---------------------+
| 1 | EM001 | 2015-07-03 10:51:19 | 2015-07-03 18:19:53 |
| 2 | EM001 | 2015-07-03 12:36:14 | 2015-07-03 18:12:29 |
| 3 | EM001 | 2015-07-04 11:34:52 | 2015-07-04 17:21:43 |
+----+-----------+---------------------+---------------------+
But when querying the data i only need the Hours the employee worked. So I need the first start time and the last end time if the dates are overlapping so that i can calculate the hours. Again this issue is there only for days with overlapping times and there may not be overlapping times for a single employee on some days.
This hour calculation is not for employee salary purposes. Its just to capture the work hour of the user.
So does anyone have any idea on how to do this.
Thanks
Dipen Shah has a point, but sometimes you can't change the way sign-ins are logged. In this case perhaps you can try grouping the table by the date and querying the min(start) and max (end) of every user and date, like this:
select empid, min(start), max(end) from signin group by empid, date(start);
I'm trying to figure out an efficient query for a project I'm working on.
We're recording a switch state into a table, each time it changes, a row is added with the new value (0 or 1).
Here's a simplified structure of the table:
day | hour | state
-----+------+-------
10 | 1 | 1 # day 10
10 | 6 | 0
10 | 21 | 1
11 | 3 | 0 # day 11
11 | 6 | 1
13 | 13 | 0 # day 13
....
Now we need to make a daily overview, something like this:
Day 11 : Switch was on during 0-3, 6-24
SELECT * FROM log WHERE day = 11 will give us only [3,0] and [6,1]. From those we can guess that it started ON and ended ON, but how about day 12?
SELECT * FROM log WHERE day = 12 gives nothing, obviously - there's no clue to guess from.
What is an efficient and reliable way to get the starting and ending state for a given day? Something like "Select one entry before day 12 and one after day 12"?
SELECT
day,
hour,
state
FROM
log
WHERE
day*100+hour
BETWEEN
(SELECT max(day*100+hour) FROM log WHERE day < 12)
AND
(SELECT min(day*100+hour) FROM log WHERE day > 12)
Will give you everything between (including) the last entry before day 12 and the first entry after day 12.
The second part might be unnecessary if you don't need to know when the state changed, and it's enough to know the state didn't change until at least midnight of the selected day.
Suppose I have a MySQL table that looks like the following, where I keep track of when (Date) a user (User.id) read an article on my website (Article.id):
------------------------------------------
Article_Impressions
------------------------------------------
date | user_id | article_id
--------------------+---------+-----------
2013-04-02 15:33:23 | 815 | 2342
2013-04-02 15:38:21 | 815 | 108
2013-04-02 15:39:33 | 161 | 4815
...
I'm trying to determine how many session I had, as well as average session duration per user on a given day. A session ends when an article was not read within 30 minutes after another article.
Question
How can I efficiently determine how many session I had on a given day? I'm using PHP and MySQL.
My first idea is to query all that data for a given day, sorted by user. Then I iterate through each user, check if an impression was within 30 minutes of the last impression, and tally up a total count of session each user had that day.
Since we have around 2 million impressions a day on our site, I'm trying to optimize this report generator.
Try this query
Query 1:
select
#sessionId:=if(#prevUser=user_id AND diff <= 1800 , #sessionId, #sessionId+1) as sessionId,
#prevUser:=user_id AS user_id,
article_id,
date,
diff
from
(select #sessionId:=0, #prevUser:=0) b
join
(select
TIME_TO_SEC(if(#prevU=user_id, TIMEDIFF(date, #prevD), '00:00')) as diff,
#prevU:=user_id as user_id,
#prevD:=date as date,
article_id
from
tbl
join
(select #prev:=0, #prevU=0)a
order by
user_id,
date) a
[Results]:
| SESSIONID | USER_ID | ARTICLE_ID | DATE | DIFF |
-----------------------------------------------------------------
| 1 | 161 | 4815 | 2013-04-02 15:39:33 | 0 |
| 2 | 815 | 2342 | 2013-04-02 15:33:23 | 0 |
| 2 | 815 | 108 | 2013-04-02 15:38:21 | 298 |
| 3 | 815 | 108 | 2013-04-02 16:38:21 | 3600 |
This query will return a unique session for every new user and also for same user if the next article read is after 30 mins as per your requirement mentioned in your question. The diff column returns the seconds difference between the 2 articles by the same user which helps us count the sessionId. Now using this result it will be easy for you to count the average time per user and also total time per session.
Hope this helps you...
SQL Fiddle
If the concept of the user "session" is important to your analytics, then I would start logging data in your table to make querying of session-related data not such a painful process. A simple approach would be to log your PHP session ID. If your PHP session id is set to have the same 30 minute expiry, and you log the PHP session ID to this table then you would basically have exactly what you are looking for.
Of course that won't help you with your existing records. I would probably go ahead and create the session field and then back-populate it with randomly generated "session" id's. I wouldn't look for a fully SQL solution for this, as it may not do what you want in terms of handling edge cases (sessions spanning across days, etc.). I would write a script to perform this backfill, which would contain all the logic you need.
My general approach would be to SELECT all the records like this:
SELECT user_id, date /* plus any other fields like unique id that you would need for insert */
FROM Article_Impressions
WHERE session_id IS NULL
ORDER BY user_id ASC, date ASC
Note: make sure you have index on both user_id and date fields.
I would then loop through the result set, building a temp array of each user_id, and loop through that array for all date values assigning a randomly generated session id which would change each time the date change was greater than 30 minutes. Once the user value increments, I would make inserts for that previous user to update the session_id values and then reset the temp array to empty and continue that process with the next user.
Note that it is probably important to take the approach of keeping a relatively small temp/working array like this, as with the number of records you are talking about, you are likely not going to be able to read the entire result set into an array in memory.
Once your data is populated, the query becomes trivial:
Unique sessions for each day:
SELECT DATE(date) as `day`, COUNT(DISTINCT session_id) AS `unique_sessions`
FROM Article_Impressions
GROUP BY `day`
ORDER BY `day` DESC /* or ASC depending on how you want to view it */
Average sessions per day:
SELECT AVG(sessions_per_day.`unique_sessions`) AS `average_sessions_per_day`
FROM
(
SELECT DATE(date) as `day`, COUNT(DISTINCT session_id) AS `unique_sessions`
FROM Article_Impressions
GROUP BY `day`
) AS sessions_per_day
GROUP BY sessions_per_day.`day`
Note: you need an index on the new session_id field.