Highscores - Best time period for a user - php

I have a table which keeps track of data from a game, here is an example of the table:
id | player_name | date | score | kills
1 | test1 | 2013-01-01 00:00:00 | 10000 | 200
2 | test1 | 2013-01-01 00:01:00 | 12000 | 300
I have a leaderboards for players, it ranks people who gain the most score/kills, etc. in a certain time period. At the moment I have only got it so that it ranks players in the previous 24 hours. I am doing this by selecting the first and last records in a specified time period and then subtracting them to get the difference.
This is my current query:
SELECT date, score FROM datapoints WHERE player_name = :player AND date = (SELECT MIN(date) FROM datapoints WHERE player_name = :player AND date > DATE_SUB(CURDATE(), INTERVAL 24 HOUR))
UNION ALL
SELECT date, score FROM datapoints WHERE player_name = :player AND date = (SELECT MAX(date) FROM datapoints WHERE player_name = :player AND date > DATE_SUB(CURDATE(), INTERVAL 24 HOUR))
After subtracting I use the PHP arsort() function to order them and then display them on the page.
However, I want to add another feature. I want to be able to see the on which day was the users best day for score/kills.
I have been thinking of how I could possibly do it and one was was using the above query but having a loop for each day and taking out the best day, however this probably isn't very efficient and I was wondering, if there was a better way of doing this?

Here is how you would get the score changes and kills that occur on any given calendar day:
select date(date) as thedate, max(score) - min(score) as DayScore,
max(kills) - min(kills) as DayKills
from datapoints dp
where player_name = :player
group by date(date);
To get the top day for scores, for instance, you would add an order by and limit clause like this:
order by DayScore desc
limit 1;

Related

SQL query for extract the highest value at a given time range?

I have a problem on a sql query. I need to take the last 30 days and then remove only the 4 results with the "voting" value greater
db structure
Id | time | voting
1 | unix time | 3
2 | unix time | 2
3 | unix time | 4
4 | unix time | 1
5 | unix time | 6
I would like to take me only the data of: 5-3-1-2
I have tried with
select a.*
from table a
inner join
( select votingng, max(time) as latest from table group by voting) v
on a.time = v.latest
and a.voting = v.voting
order by time desc limit
It sounds like you are trying to get the top 4 voting results in the past 30 days. Does either of these give you what you want?
SELECT a.*
FROM table a
WHERE a.time > UNIX_TIMESTAMP(DATE_SUB(CURDATE(), INTERVAL 30 DAY))
ORDER BY a.voting DESC
LIMIT 4;
or
SELECT a.*
FROM table a
WHERE DATEDIFF( NOW(), FROM_UNIXTIME(a.time) ) <= 30
ORDER BY a.voting DESC
LIMIT 4;
I think this is what you want:
select v.*
from voting v
where timestamp >= unix_timestamp(date_sub(curdate(), interval 1 month)
order by voting desc
limit 4;
Hope this is what you are looking for:
Select *
From
Voting
Where
time Between CURDATE() And DATE_SUB(CURDATE(),INTERVAL 30 DAY)
Order By voting Desc
Limit 4
Try this if you are using teradata
SELECT * from table
qualify row_number () over(order by time desc)=1 ;
or
select * from
(select table.*, row_number () over(order by time desc) as RANK from table)
where RANK=1

Mysql query based on date?

I have a table like this
id | date | content
1 | 09-16-2013 | content 1 here
2 | 09-23-2013 | content 2 here
3 | 09-30-2013 | content 3 here
I would like to display the content for a week from that date. For example, the first content should start on 9/16/2013 and then show until 9/22/2013 mid night. then on next day, it changes to the content 2.
Same way,when I am on content 2, I want to display like "previous week content" and then show just the previous ones..I think I can do this by checking the current date and then anything below that has to be displayed.
I am not very good at these kind of mysql queries, please advise!
Regards
I guess you're looking for something like this
SELECT *
FROM table1
WHERE date BETWEEN CURDATE() + INTERVAL 0 - WEEKDAY(CURDATE()) DAY
AND CURDATE() + INTERVAL 6 - WEEKDAY(CURDATE()) DAY
This query will grab a row(s) where date column is within the boundaries of the current calendar week (from Monday to Sunday).
WEEKDAY() function returns the weekday index for date (0 = Monday, 1 = Tuesday, … 6 = Sunday). The expression
CURDATE() + INTERVAL 0 - WEEKDAY(CURDATE()) DAY
returns a date for Monday of the current calendar week and
CURDATE() + INTERVAL 6 - WEEKDAY(CURDATE()) DAY
returns a date for Sunday of the current calendar week.
Using BETWEEN in WHERE clause makes sure that a query returns only rows with date values that falls between these two dates (Monday through Sunday).
Note: Make sure that you have an index on date column. This query is index-friendly.
Sample output for today's date (09/19/2013):
+------+------------+----------------+
| id | date | content |
+------+------------+----------------+
| 1 | 2013-09-16 | content 1 here |
+------+------------+----------------+
UPDATE: To get records for previous calendar week you just substract 1 week interval from both values in BETWEEN
SELECT *
FROM table1
WHERE date
BETWEEN CURDATE() + INTERVAL 0 - WEEKDAY(CURDATE()) DAY - INTERVAL 1 WEEK,
AND CURDATE() + INTERVAL 6 - WEEKDAY(CURDATE()) DAY - INTERVAL 1 WEEK
Try this
SELECT * FROM table WHERE date BETWEEN '09-16-2013' AND '09-22-2013';
keyword is WEEK()
SELECT id,date, CONCAT('content ',WEEK(date),' to here') as content FROM table_name
SELECT *
FROM table
WHERE date BETWEEN '9/16/2013 00:00:00.00' AND '9/22/2013 00:00:00.00'
You can replace the week offset to your needs
SET #weekOffset = +2;
SELECT * FROM test
WHERE WEEK(`date`) = WEEK(NOW()) + #weekOffset;
See a working demo here
To select it dynamically, try something like
SELECT * FROM `yourTable` WHERE NOW() >= STR_TO_DATE(`date`, '%m-%d-%Y') ORDER BY STR_TO_DATE(`date`, '%m-%d-%Y') DESC LIMIT 1
or t
SELECT * FROM `yourTable` WHERE CURDATE() >= STR_TO_DATE(`date`, '%m-%d-%Y') ORDER BY STR_TO_DATE(`date`, '%m-%d-%Y') DESC LIMIT 1
sqlfiddle example - http://sqlfiddle.com/#!2/62982/4

MySQL BETWEEN DATE RANGE

I have a scenario where I need to pull up delivery dates based on a table below (Example)
job_id | delivery_date
1 | 2013-01-12
2 | 2013-01-25
3 | 2013-02-15
What I'm trying to do is show the user all the delivery dates that start with the earliest (in this case it would be 2013-01-12) and add an another 21 days to that. Basically, the output I would expect it to show of course, the earliest date being the starting date 2013-01-12 and 2013-01-25. The dates past the February date are of no importance since they're not in my 21 date range. If it were a 5 day range, for example, then of course 2013-01-25 would not be included and only the earliest date would appear.
Here is main SQL clause I have which only shows jobs starting this year forward:
SELECT date, delivery_date
FROM `job_sheet`
WHERE print_status IS NULL
AND job_sheet.date>'2013-01-01'
Is it possible to accomplish this with 1 SQL query, or must I go with a mix of PHP as well?
You can use the following:
select *
from job_sheet
where print_status IS NULL
and delivery_date >= (select min(delivery_date)
from job_sheet)
and delivery_date <= (select date_add(min(delivery_date), interval 21 day)
from job_sheet)
See SQL Fiddle with Demo
If you are worried about the dates not being correct, if you use a query then it might be best to pass in the start date to your query, then add 21 days to get the end date. Similar to this:
set #a='2013-01-01';
select *
from job_sheet
where delivery_date >= #a
and delivery_date <= date_add(#a, interval 21 day)
See SQL Fiddle with Demo
SELECT date,
delivery_date
FROM job_sheet
WHERE print_status IS NULL
AND job_sheet.date BETWEEN (SELECT MIN(date) FROM job_sheet) AND
(SELECT MIN(date) FROM job_sheet) + INTERVAL 21 DAY
SELECT j.job_id
, j.delivery_date
FROM `job_sheet` j
JOIN ( SELECT MIN(d.delivery_date) AS earliest_date
FROM `job_sheet` d
WHERE d.delivery_date >= '2013-01-01'
) e
ON j.delivery_date >= e.earliest_date
AND j.delivery_date < DATE_ADD(e.earliest_date, INTERVAL 22 DAY)
AND j.print_status IS NULL
ORDER BY j.delivery_date
(The original query has a predicate on job_sheet.date; the query above references the d.delivery_date... change that if it is supposed to be referencing the date column instaed.)
If the intent is to only show delivery_date values from today forward, then change the literal '2013-01-01' to an expression that returns the current date, e.g. DATE(NOW())

MySQL - count users WHERE (last 30 days, last one year, all time)

I am trying to make a query that checks the clients table and returns a count of users with a specific value for the last 30 days, 365 days and All Time.
The all time count is easy:
$stmt = $conn->prepare("SELECT count(id) AS count FROM clients WHERE referred = :refid");
$stmt->bindParam(':refid', $refid);
$stmt->execute();
$totalreferrals = $stmt->fetchAll();
Table:
id | signup | reffered |
----------------------------
2 | 2012-08-24 | 14 |
----------------------------
3 | 2011-10-13 | 14 |
I am not sure if I can combine the query using a UNION or if I should just make three different queries. Any help?
i think you want this in columns and not in rows if so here it is
SELECT COUNT(CASE WHEN DATEDIFF(CURDATE(),signup) <= 30 THEN id
ELSE NULL
END) AS Last30days ,
COUNT(CASE WHEN DATEDIFF(CURDATE(), signup) <= 365 THEN id
ELSE NULL
END) AS Last365Days ,
COUNT(*) AS Alltime
FROM Table1
WHERE reffered = 14
SQLFiddle http://sqlfiddle.com/#!2/6e6ce/2
Maybe this could solve the problem:
SELECT count(id) AS count FROM clients WHERE referred = :refid AND BETWEEN ADDDATE(NOW(), INTERVAL -1 MONTH) AND NOW();
SELECT count(id) AS count FROM clients WHERE referred = :refid AND BETWEEN ADDDATE(NOW(), INTERVAL -1 YEAR) AND NOW();

Find first free date in agenda

in my component I have created an agenda, where user can save their appointments.
Agenda table is quite simple: there is a title, description and start/end datetime fields.
When a user adds a new event, I'd wish to hint him with the first empty spot.
How can I achieve that?
Is that possible with a single/bunch queries, or I have to create a loop until I find the first empty spot?
For example this is my table:
| ID | Start date | End date |
| 1 | 2012-06-14 09:00:00 | 2012-06-14 09:32:00 |
| 2 | 2012-06-14 15:00:00 | 2012-06-14 15:45:00 |
| 3 | 2012-06-14 18:20:00 | 2012-06-14 18:55:00 |
The first free datetime should be 2012-06-14 09:33:00, how can I fetch this date?
Interesting challenge to be done in one query :) Took me a while but I came with solution. With these assumptions:
minimum appointment duration is 30 minutes
appointment starts and ends in one day
day starts at 9:00 and ends at 17:00
minimum interval between ending and starting times is 1 minute
There are 4 cases to take into consideration:
There is some free time in the morning
There is some free time during the day
First free slot is next day to the last appointment in db
You have all free slots from now on
So yo have to select minimum form these dates.
And the query:
SELECT
MIN(next_start_date) AS next_start_date
FROM
(
(
SELECT
DATE_FORMAT(t1.start_date,'%Y-%m-%d 09:00:00') AS next_start_date
FROM
agenda t1
WHERE
t1.start_date > NOW()
AND
TIME(t1.start_date) > '09:30:00'
AND
NOT EXISTS(
SELECT 1 FROM agenda t2 WHERE DATE(t2.start_date) = DATE(t1.start_date) AND TIME(t2.start_date) <= '09:30:00'
)
LIMIT 1
)
UNION
(
SELECT
t3.end_date + INTERVAL 1 MINUTE AS next_start_date
FROM
agenda t3
WHERE
t3.start_date > NOW()
AND
TIME(t3.start_date) >= '09:00:00'
AND
TIME(t3.end_date) < '16:30:00'
AND NOT EXISTS
(SELECT 1 FROM agenda t4 WHERE TIMESTAMPDIFF(MINUTE,t3.end_date,t4.start_date) BETWEEN 0 AND 30 )
ORDER BY
t3.start_date ASC
LIMIT 1
)
UNION
(
SELECT CONCAT(CAST(DATE((SELECT MAX(t5.start_date) + INTERVAL 1 DAY FROM agenda t5 WHERE t5.start_date > NOW())) AS CHAR), ' 09:00:00') AS next_start_date
)
UNION
(
SELECT
IF(
TIME(NOW()) < '09:00:00',
DATE_FORMAT(NOW(),'%Y-%m-%d 09:00:00'),
IF(
TIME(NOW()) < '16:30',
NOW(),
DATE_FORMAT(NOW() + INTERVAL 1 DAY,'%Y-%m-%d 09:00:00' )
)
) AS next_start_date
FROM
(SELECT 1) t6
WHERE NOT EXISTS(
SELECT 1 FROM agenda t7 WHERE t7.start_date > NOW()
)
LIMIT 1
)
) t
Of course it is not perfect - when there next free slot occurs in the next day, there's a chance that it is Saturday or other day off from work. Taking it into consideration, the best way will be to check if returned is valid work day, if not then repeat the query with NOW() replaced by datestring of next valid work day.

Categories