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

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

Related

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

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.

How to show online users in the top and offline after it?

Could you guys please tell me how to show all online people on the top and all offline after, both lists in ascending order of the username just like Skype does.
My MySQL table is Users, and the columns are as follow:
ID
Username
Last_logged_in - is with unix_timestamp();
the code I am using to show online people is as follow:
select * from users where Last_logged_in >= UNIX_TIMESTAMP() - 60;
and the code I tried was like so:
select id, username, last_logged_in from users where last_logged_in >= UNIX_TIMESTAMP() - 60 UNION select id, username, last_logged_in from users where last_logged_in <= UNIX_TIMESTAMP() - 60 LIMIT 10;
some helps will be really appreciated.
Your query doesn't provide the results you expect because UNION does not preserve the order of the rows from the queries it unions.
You need to enclose each of the unioned queries into parentheses and add ORDER BY after the last query. However, if you do that you obtain a big and slow query that selects all the records from table users in a convoluted way.
The solution is to order the rows descending by column Last_logged_in. This way, the users that logged in recently are returned first. Also you need to add in the fields list the expression that tells if the user is still online. Finally, because your query does not filter the returned users, a LIMIT clause is recommended; otherwise the query will return the entire table which is probably not what you want.
Update
As the OP specified in a comment, the users must be sorted by their online status (online first) and then by their usernames (ascending).
The (updated) query is:
SELECT u.*, IF(Last_logged_in >= UNIX_TIMESTAMP() - 60, 1, 0) as isOnline;
FROM users u
ORDER BY isOnline DESC, username ASC
LIMIT 20
No need for union, just order by the last_logged_in field descending, since you use this field to calculate if a user is logged in or not:
select * from users order by Last_logged_in desc limit 10;
This way the logged in users will be on the top of the list because they loggen in most recently.
UPDATE
Still no need for union if you want to order both lists by username, let's build on axiac's proposed solution:
SELECT u.*, IF(Last_logged_in >= UNIX_TIMESTAMP() - 60, 1, 0) as isOnline;
FROM users u
ORDER BY isOnline DESC, u.Username ASC

Remove all entries except last 15 from database for each UserID

I have a SQL server database and I would like to delete every row except the last 15, but, I need this to be per 'UserID'.
My database contains entries for a number of different users, where their ID is column 'UserID', so I want each user to have 15 entries in the database and the old ones to be removed.
What would the SQL be for this?
Here is an example effort from myself:
$sql = "DELETE FROM SocialSenseTracking WHERE UserID NOT IN (SELECT TOP 15 UserID='$user' FROM SocialSenseTracking ORDER BY UserID DESC)";
You can use a CTE and row_number() for this:
with todelete as (
select sst.*, row_number() over (partition by UserId order by CreatedAt desc) as seqnum
from SocialSenseTracking sst
)
delete from todelete
where seqnum > 15;
You don't specify the column used to determine the most recent records, so I just invented CreatedAt.

Pulling Last Two Dates PHP/MySQL

I have a table in my database which is updated randomly. I'm trying to pull entries by the latest date. This part is simply and I can do it with ease. However, I want to pull the two latest dates.
Example; If my last update was 2015-06-22 and the one before than was 2015-06-12 and the one before then was 2015-06-02. I would want to pull 2015-06-22 and 2015-06-15.
I would use a LIMIT 2, however, there are an unknown amount of items that may have the same date attached.
I haven't tried anything other than the LIMIT 2. After some research, I wasn't able to find anything to reference.
Update
I used SELECT DISTINCT to get the desired results.
SELECT DISTINCT dates FROM table ORDER BY dates DESC LIMIT 2
Will give you the latest 2 dates in the table.
I would have a column set to id, that is auto incremented, and do my query like this:
SELECT * FROM tbl_name ORDER BY `id` DESC LIMIT 2
Crap McAdam you beat me to it!
You can get the latest two dates using LIMIT, like you mentioned:
SELECT latestDates
FROM myTable
ORDER BY dateColumn DESC
LIMIT 2;
And you can join that to your original table to only select rows that occur on those two dates:
SELECT m.*
FROM myTable m
JOIN(
SELECT latestDates
FROM myTable
ORDER BY dateColumn DESC
LIMIT 2) tmp ON tmp.latestDates = m.dateColumn;

How can I select users who have not submitted records using php and mysql?

I have columns in my database for date_created (format 2014-07-08 11:25:29) and username. I want to create a conditional statement which will display users who have not submitted a new record within the last week. I've never really queried my database for an action NOT taking place. How might I achieve this?
SELECT username
FROM records
GROUP BY
username
HAVING MAX(date_created) < NOW() - INTERVAL 1 WEEK
Note, however, that this query won't return users who haven't created a single record.
If you have another table holding all user records (including those who had no records in records), use this query:
SELECT u.username
FROM users u
WHERE NOT EXISTS
(
SELECT NULL
FROM records r
WHERE r.username = u.username
AND r.date_created >= NOW() - INTERVAL 1 WEEK
)
In both cases, make sure you have an index on records (username, date_created) for the queries to work fast.

Categories