Getting the top scores, but remove duplicate users (SQL) - php

I'm working on a time based game (where a lower time is better), and I have a leaderboard for it, which stores every playthrough into a SQL database.
I'd like to get the top 15 lowest (best) times from the database, but only show one output for each user, so that the best times of the top 15 users are displayed, but I can't seem to do it while returning all of the information.
The Query I'm using is:
SELECT * FROM `scores` WHERE size='$size' ORDER BY `time` ASC LIMIT 15
Thank you.

If you group your data using the user column, you can use MIN() to isolate the lowest/best time for each users. Finally, you sort by BestTime ASC (so that lower numbers are listed first) and truncate the result set with LIMIT.
Query:
SELECT `user`, MIN(`time`) AS BestTime
FROM `scores`
WHERE `size` = '10x10'
GROUP BY `user`
ORDER BY `BestTime`
LIMIT 15;

SELECT * FROM (SELECT user,size,min(time) as time FROM scores
WHERE size = '10x10'
GROUP BY user, size)
ORDER BY time
LIMIT 15
Selects minimum time for each users and returns top 15 users with their min time score.

You would appear to want something like this:
select s.*
from scores s
where s.score = (select max(s2.score) from scores s2 where s2.userid = s.userid)
order by s.score asc
limit 15;
I have no idea what size is for in your sample query.

Related

Why do I get results from a different row in MySQL?

Using this query,
SELECT username, MAX(wordpermin) as maxword,date_created FROM user_records where DATE(date_created) = CURDATE() GROUP BY(username) ORDER BY maxword DESC LIMIT 20
I am trying to query a limit of 20 of the top wordpermin by their username and the time created and that by calling date_created in the current 24 hours.
The problem I have is when I have a new high wordpermin. Instead of giving me also the new date_created, it keeps the old value of date_created. I even looked into my database and I made sure I have date_created updated. How can this happen?
I mean, I have two values from different rows.
The following query gives you the last date where a user has the maxword.
Your query would not run when you activated ONLY_FULL_GROUP_BY.
You should always specify for every column which aggregation function you want to use, because SQL rows don't have any order and every column will be selected on its own.
I selected Max (date_created), so that MySQL knows which date to show, because if there were more than one date with the same maximum word, MySQL would show all.
SELECT
u.username, u1.maxword, MAX(u.date_created)
FROM
user_records u
INNER JOIN
(SELECT
username,DATE(date_created) date_created, MAX(wordpermin) AS maxword
FROM
user_records
GROUP BY username,DATE(date_created)) u1 ON u.username = u1.username
AND u.wordpermin = u1.maxword AND Date(u.date_created) = DATE(u1.date_created)
WHERE
DATE(u.date_created) = CURDATE()
GROUP BY (username)
ORDER BY maxword DESC
LIMIT 20;
LIMIT 20
Examole http://sqlfiddle.com/#!9/857355/2

Get non duplicate random element using MySQL and PHP

I have a scenario, where I need to find a random winner from a group of entries.
The entries can be multiple times and now I am fetching all the records grouped by user ID and using PHP's array_rand() method to find a random winner. The grouping is used to avoid duplicate elements.
Here I am facing two problems
The query is timing out as it is dealing with almost 10000000 records.
PHP memory is exhausted because of large number of records.
My current query is a simple one and it looks like this
SELECT id, userID from table where id!= 1111 and created_at >='2017-08-10' group by userID
What is the best method, which will work on this large-scale?
Use ORDER BY RAND() and limit results to 1 to avoid memory getting exhausted.
SELECT id, userID
from table
where id!= 1111 and created_at >='2017-08-10'
group by userID
ORDER BY RAND()
LIMIT 1;
Try doing everything in SQL , might be faster.
SELECT id, userID
FROM table
WHERE id!= 1111 and created_at >='2017-08-10'
GROUP BY userID
ORDER BY RAND()
LIMIT 1;
May this will help
SELECT userID
FROM table AS t1 JOIN
(SELECT CEIL(RAND() *
(SELECT MAX(userID)
FROM table)) AS userID)
AS t2
where id!= 1111 and created_at >='2017-08-10'
ORDER BY t1.userID ASC
LIMIT 1

Performing arithmetic in SQL query

So I'm working on a script that awards "trophies" to the top 4 performers of a game. The table logs each "grab" attempt, the user that performed it, and whether it was successful. I'd like to create a script that is able to pull the top four off of percentage of successful grabs (attempts / successes)
Is something like this possible within the query itself using mysqli?
I have successfully accomplished the code already by just looping through each table entry, but with thousands of attempts per month it just seems like a clunky way to go about it.
Here is an example of a row in the table, I am attempting to grab the top four based off of monthlyTries/monthlySuccessful
id userId PetId PalId tries successfulGrabs monthlyTries MonthlySuccessful
5 44550 84564 3967 825 268 120 37
Assuming you have a success column that's either 1 or 0 you can sum the success and divide that by count(*) which is the total # of attempts
select user_id, sum(success)/count(*) percentage
from attempts a
group by user_id
order by percentage desc
limit 4
If the success column is not a 1/0 value you can use conditional aggregation
select user_id, sum(case when success = 'yes' then 1 else 0 end)/count(*) as percentage
from attempts a
group by user_id
order by percentage desc
limit 4
In MySQL, you can simplify the logic. If success takes on the values 0 and 1:
select a.user_id, avg(success) as percentage
from attempts a
group by a.user_id
order by percentage desc
limit 4;
Otherwise:
select a.user_id, avg(success = 'yes') as percentage
from attempts a
group by a.user_id
order by percentage desc
limit 4;

PHP MYSQL search based on rating and timestamp

My search query runs like:
select * from posts p where p.post like '%test%' ORDER BY p.upvotes DESC,
p.unix_timestamp DESC LIMIT 20
If there are more than 20 results for the searched keyword, i find out the minimum timestamp value, store it in a hidden element and run another query to Load More results like:
select * from posts p where p.post like '%test%' and p.unix_timestamp < 1360662045
ORDER BY p.upvotes DESC, p.unix_timestamp DESC LIMIT 20
Whats really happening is that my first query is ignoring (Obviously, my mistake) posts which haven't had any votes(meaning 0 votes) because of my ORDER BY p.upvotes DESC and as a result of this, i noticed that it fetched the first post in the table in the first 20 results, so the minimum timestamp becomes first post's timestamp. Now after this, if i try to fetch the next 20 results which is less than the minimum timestamp, it doesn't give anything.
Right now, i am simply using the upvotes ordering to fetch top records. Should i be using some algorithm like Bayesian Average or some other algorithm?
Please advise how i can improve the queries if i had to stay with current system of ordering or is there any viable and more efficient method i should be using?
P.S. If possible, please refer some resources about the Bayesian Average(it seems to be most used) or some other alternative?
Storing the timestamp when you first do a search and then using that for the next query you could use something like this:-
$sql = "SELECT *
FROM posts p
LEFT OUTER JOIN (SELECT post_id, COUNT(*) FROM post_ratings WHERE timestamp_rated <= $SomeTimeStoredBetweenPages GROUP BY post_id) pr ON p.id = pr.post_id
WHERE p.post like '%test%'
ORDER BY pr.post_ratings DESC, p.unix_timestamp
DESC LIMIT ".(($PageNo - 1) * 20)." 20";
This is very much an example as I have no real idea of you table structures. Also not sure if you just have a row for each up vote, or whether there are down votes to take account of as well.

Selecting random entry from MySQL Database

How can I select a single random entry from a MySQL database using PHP?
I want to select the Author, AuthorText, and Date?
SELECT Author, AuthorText, Date FROM table ORDER BY RAND() LIMIT 1
Take a look to this interesting article:
“Do not use ORDER BY RAND()” or “How to get random rows from table?”
ORDER BY rand() LIMIT 1
will sort all the rows in the table, which can be extremely slow.
Better solution : say your table has the usual primary key auto-increment field, generate a rendom number between min(id) and max(id) and select the closest id.
It will not be as random as a "true" random selection, because a id after a large hole of deleted ids will have a higher probability of being chosen. But it will take 50 µs instead of 2 seconds if your table is large...
SET #t = (SELECT FLOOR(a + (b-a)*rand()) FROM (SELECT min(id) as a, max(id) as b FROM table)
SELECT * FROM table WHERE id>#t ORDER BY id LIMIT 1;
You can order by a random & restrict to 1 row as follows:
select
author, authortext, date
from bookstable
order by rand()
limit 1

Categories