SQL query - How to display points in the last 24 hours? - php

I'm building a website with points system, similar to Stackoverflow;
This is the code I'm using to display top users (for all time):
SELECT id, username, active, points
FROM users
WHERE active='1'
ORDER BY points DESC
But how can I show the top users in 24 hours (also points)?

You would have to make a special table that would record when (and how many) points the user received.
EDIT
E.g. table points
user_id time awarded_points
-------------------------------------
1 1298745681 10
...
Then you just ask for the points awarded today with WHERE time > UNIX_TIMESTAMP(CURDATE()) or in the last 24 hours WHERE time > UNIX_TIMESTAMP()-24*3600.
Example use:
SELECT u.id, u.username, u.active, SUM(p.awarded_points) AS points
FROM points AS p
LEFT JOIN users AS u ON u.id = p.user_id
WHERE time > UNIX_TIMESTAMP(CURDATE())
AND u.active = '1'
GROUP BY p.user_id
ORDER BY points DESC
I'd also suggest adding a LIMIT to the query, especially if your site grows big.

Your need another table, where all users activites/points would be write
And than join with this table, and condition to 24h

Add a table recording the points each user receives and when with a foreign key relation to the users table
For example a table named points with the following columns
userid (FK to users table)
datetimeallocated
numberofpoints
other columns of interest e.g. user who allocated the points etc
You then need to query this table e.g.
SELECT SUM(numberofpoints), userid
FROM points
WHERE datetimeallocated >= DATE_SUB(CURDATE(), INTERVAL 1 DAY)
GROUP BY userid
ORDER BY SUM(numberofpoints) DESC

Related

Getting ordered rows partly

Hello developers out there,
I want to create a ranking list in my program, and for that want to get the users of the mysql database ordered by their points. I'm doing this with:
select `name`,`points` from users order by `points` desc
For better performance i don't want to get all users but just 10+ and 10- from a given user, because i don't want to show the whole ranking list in the program anyways. Could somebody help me with this?
One method uses subqueries and union all:
(select name, points
from users
where points <= (select u2.points from users u2 where u2.name = ?)
order by points desc
limit 11
) union all
(select name, points
from users
where points > (select u2.points from users u2 where u2.name = ?)
order by points asc
limit 10
) ;
This returns 21 rows, with the specified user included.

PHP mysqli. ORDER SELECT after one table but SELECT data from another table?

I have 2 tables.
visitors:
pageID
visitorID
last_visit
users:
userID(this ID and the pageID and visitorID in visitors is bundled to the same exact user)
username
age
I want to select last 5 visitors of the current logged in user (ORDER BY last_visit LIMIT 5 in the table visits)
I want to select the data from table users of those 5 users.(username, age, etc.)
How do i do this?
Use a JOIN with a subquery that gets the last 5 visitors.
SELECT u.*
FROM users AS u
JOIN (SELECT visitorId
FROM visitors AS v
WHERE v.pageID = $currentUserID
ORDER BY last_visit
LIMIT 5) AS v1
ON u.userID = v1.visitorID

How do I select users that have not had their score updated within the last 2 hours or at all using Mysql

I have the following 2 tables...
users
user_id, name, age
user_score
score_id, user_id, score, date(timestamp)
The user_score table should keep a log of all scores for all users updated every 2 hours.
So I need to get a list of all user ids that have not had their score updated in the last 2 hours or at all (for new players). I'm guessing I will have to use INNER JOIN?
Any help would be greatly appreciated.
You want a left join or not exists. You simply need all records with no activity in the past two hours (this would include new users too):
select u.*
from users u
where not exists (select 1 from user_score us
where u.user_id = us.user_id and
us.date >= date_sub(now(), interval 2 hour)
);

MySQL, Need to select rows that has the most frequent values in another table

I'm kind of new to SQL and I can't find the solution to my problem. I have two tables. In table A, I'm storing a lot of comments, each with a unique ID.
In table B, I'm storing every vote (like=1 and dislike=0) for every comment with a datetime. There will be an entry for every vote, so there will be tons of rows for each comment in table A.
I need to retrieve all the comments and sort them such that the weekly most liked comments are at the top, but I'm not sure how.
Here's what I have so far, but not sure how to continue:
SELECT * FROM comment INNER JOIN logs ON comment.c_id=logs.c_id WHERE logs.daterate >= DATE_SUB(CURDATE(), INTERVAL 8 DAY) AND logs.rated=1
To clarify, I need to get all entries from logs with rated = 1 in the past week and sort them by the most frequent c_id in descending order, and get distinct c_id for each row... if that makes sense
Please ask questions if I didn't make it clear enough, thanks!!
SELECT *
FROM comment
INNER JOIN (SELECT comment.c_id,
COUNT(*) AS cnt
FROM comment
INNER JOIN logs ON comment.c_id=logs.c_id
WHERE logs.daterate >= DATE_SUB(CURDATE(), INTERVAL 8 DAY)
AND logs.rated=1
GROUP BY comment.c_id) x ON x.c_id = comment.c_id
ORDER BY x.cnt DESC
Try this -
I have first queried all records from logs table which are rated 1 and are from 7 days from current date and also are ordered based on the count of c_id. Then joined this with the COmments table.
SELECT Comment.* FROM comment C
INNER JOIN (SELECT logs.c_id as c_id,count(logs.c_id) as logcount FROM logs
WHERE logs.rated=1
AND logs.daterate BETWEEN GETDATE() AND DATEADD(day,-7,getdate())
Group by logs.c_id
order by count(logs.c_id) desc) X
ON C.c_id = X.c_id
ORDER BY X.logcount DESC

Get multiple GROUP BY results per group, or use separate concatenated table

I am working on an auction web application. Now i have a table with bids, and from this table i want to select the last 10 bids per auction.
Now I know I can get the last bid by using something like:
SELECT bids.id FROM bids WHERE * GROUP BY bids.id ORDER BY bids.created
Now I have read that setting an amount for the GROUP BY results is not an easy thing to do, actually I have found no easy solution, if there is i would like to hear that.
But i have come up with some solutions to tackle this problem, but I am not sure if i am doing this well.
Alternative
The first thing is creating a new table, calling this bids_history. In this table i store a string of the last items.
example:
bids_history
================================================================
auction_id bid_id bidders times
1 20,25,40 user1,user2,user1 time1,time2,time3
I have to store the names and the times too, because I have found no easy way of taking the string used in bid_id(20,25,40), and just using this in a join.
This way i can just just join on auction id, and i have the latest result.
Now when there is placed a new bid, these are the steps:
insert bid into bids get the lastinserteid
get the bids_history string for this
auction product
explode the string
insert new values
check if there are more than 3
implode the array, and insert the string again
This all seems to me not a very well solution.
I really don't know which way to go. Please keep in mind this is a website with a lot of bidding's, they can g up to 15.000 bidding's per auction item. Maybe because of this amount is GROUPING and ORDERING not a good way to go. Please correct me if I am wrong.
After the auction is over i do clean up the bids table, removing all the bids, and store them in a separate table.
Can someone please help me tackle this problem!
And if you have been, thanks for reading..
EDIT
The tables i use are:
bids
======================
id (prim_key)
aid (auction id)
uid (user id)
cbid (current bid)
created (time created)
======================
auction_products
====================
id (prim_key)
pid (product id)
closetime (time the auction closses)
What i want as the result of the query:
result
===============================================
auction_products.id bids.uid bids.created
2 6 time1
2 8 time2
2 10 time3
5 3 time1
5 4 time2
5 9 time3
7 3 time1
7 2 time2
7 1 time3
So that is per auction the latest bids, to choose by number, 3 or 10
Using user variable, and control flow, i end up with that (just replace the <=3 with <=10 if you want the ten auctions) :
SELECT a.*
FROM
(SELECT aid, uid, created FROM bids ORDER BY aid, created DESC) a,
(SELECT #prev:=-1, #count:=1) b
WHERE
CASE WHEN #prev<>a.aid THEN
CASE WHEN #prev:=a.aid THEN
#count:=1
END
ELSE
#count:=#count+1
END <= 3
Why do this in one query?
$sql = "SELECT id FROM auctions ORDER BY created DESC LIMIT 10";
$auctions = array();
while($row = mysql_fetch_assoc(mysql_query($sql)))
$auctions[] = $row['id'];
$auctions = implode(', ', $auctions);
$sql = "SELECT id FROM bids WHERE auction_id IN ($auctions) ORDER BY created LIMIT 10";
// ...
You should obviously handle the case where, e.g. $auctions is empty, but I think this should work.
EDIT: This is wrong :-)
You will need to use a subquery:
SELECT bids1.id
FROM ( SELECT *
FROM bids AS bids1 LEFT JOIN
bids AS bids2 ON bids1.created < bids2.created
AND bids1.AuctionId = bids2.AuctionId
WHERE bid2.id IS NULL)
ORDER BY bids.created DESC
LIMIT 10
So the subquery performs a left join from bids to itself, pairing each record with all records that have the same auctionId and and a created date that is after its own created date. For the most recent record, there will be no other record with a greater created date, and so that record would not be included in the join, but since we use a Left join, it will be included, with all the bids2 fields being null, hence the WHERE bid2.id IS NULL statement.
So the sub query has one row per auction, contianing the data from the most recent bid. Then simply select off the top ten using orderby and limit.
If your database engine doesn't support subqueries, you can use a view just as well.
Ok, this one should work:
SELECT bids1.id
FROM bids AS bids1 LEFT JOIN
bids AS bids2 ON bids1.created < bids2.created
AND bids1.AuctionId = bids2.AuctionId
GROUP BY bids1.auctionId, bids1.created
HAVING COUNT(bids2.created) < 9
So, like before, left join bids with itself so we can compare each bid with all the others. Then, group it first by auction (we want the last ten bids per auction) and then by created. Because the left join pairs each bid with all previous bids, we can then count the number of bids2.created per group, which will give us the number of bids occurring before that bid. If this count is < 9 (because the first will have count == 0, it is zero indexed) it is one of the ten most recent bids, and we want to select it.
To select last 10 bids for a given auction, just create a normalized bids table (1 record per bid) and issue this query:
SELECT bids.id
FROM bids
WHERE auction = ?
ORDER BY
bids.created DESC
LIMIT 10
To select last 10 bids per multiple auctions, use this:
SELECT bo.*
FROM (
SELECT a.id,
COALESCE(
(
SELECT bi.created
FROM bids bi
WHERE bi.auction = a.id
ORDER BY
bi.auction DESC, bi.created DESC, bi.id DESC
LIMIT 1 OFFSET 9
), '01.01.1900'
) AS mcreated
COALESCE(
(
SELECT bi.id
FROM bids bi
WHERE bi.auction = a.id
ORDER BY
bi.auction DESC, bi.created DESC, bi.id DESC
LIMIT 1 OFFSET 9
), 0)
AS mid
FROM auctions a
) q
JOIN bids bo
ON bo.auction >= q.auction
AND bo.auction <= q.auction
AND (bo.created, bo.id) >= (q.mcreated, q.mid)
Create a composite index on bids (auction, created, id) for this to work fast.

Categories