mySQL select top user with top download hits - php

Let's say I have a table that stores user info with each row structured like:
(int) FileId |(int) userId | (int) DownloadHits | (varchar) UserName
Each user may have a lots of files uploaded by their names.
I want to show a list of user that have top download hits, look like :
userId UserName DownloadHits
1 Key 120
2 Bob 50
3 Zero 15
I tried SUM method but it only show the top one user.
Is there any solution for this query ?

select userid,username,
sum(downloadhits) as theDowns
from tblName
group by userid,username
order by theDowns desc

Related

Voting SQL conundrum

I have a PHP system that allows users to vote photos on a scale of 1 - 5, what I want to do is highlight where two people give each other the same vote/score. I can't figure the SQL out at the moment for my PHP function.
The database looks like this
id, user_uid, voted_uid, score
As someone votes the id is auto incremental, the user_id is inserted from the session uid and the voted_uid comes from the image the user is viewing, then the score is the ranking from 1-5.
In theory we are therefore looking for two similar rows like this:
uid user_uid voted_uid score
7 3 5 3
38 5 3 3
At this point I want my php function to take the current users session and then match their votes and scores with other users.
In the example above I'd have the session id of 3 and I want it to return these two records as matches.
If I understand you correctly, what you want is to find pairs of rows where user_uid of the first row equals voted_uid in the second row and vice versa. But only, if score is the same in both rows.
In that case, this should do the trick:
SELECT a.*
FROM table AS a
JOIN table AS b
ON a.user_uid = b.voted_uid
AND a.voted_uid = b.user_uid
AND a.score = b.score;
If you only want rows that "mention" a specific uid, you of course have to add a WHERE user_uid = 3 OR voted_uid = 3.

How do I check for logged in user id and return that row first in a MySQL query?

The query below selects the 'loves' on an item. (think of it as similar to facebooks 'like' system.
There are two tables in use in this select. A link table (containing itemid, userid, lovetime) and this is joined to a users table in order to retrieve the username/user profile url etc.
$lovequery = "select love.lovetime, love.userid as ID, love_users.display_name, love_users.user_url
from ".$wpdb->prefix."comment_loves love
left join ".$wpdb->prefix."users love_users on love_users.ID=love.userid
where commentid = $itemid
order by love.lovetime desc
limit 4
";
The results are limited to 4 because I simply do not need any more data. The total count is stored separately in the actual item table to reduce queries.
Once the rows are retrieved from this query I iterate through the array, cross referencing against the total 'lovecount' and build a text string formatted like so:
You, John Smith, Joe Bloggs and 4 others love this.
This works fine however it fails if the logged in user (YOU) does not have the most recent 'lovetime'
What I want to do is have the currently logged in use always at the top of the returned results even if his/her 'lovetime' is older than the 4 most recent ones so that the string always begins with 'You' if the logged in user has 'loved' this item.
The logged in user id is available in the script as $userid.
To clarify
if I have the following table (the timestamps are written as simple UK dates for legibility purposes):-
userid commentid lovetime
34 3 02/10/2011
24 3 03/10/2011
13 3 06/10/2011
65 3 14/10/2011
1* 3 10/09/2011
* with userid 1 being the logged in user id
I would only get user id's 34,24,13,65 returned in that order due to ordering by 'lovetime'
What I want is for the results to return ideally 1,34,24,65. if that proves too tricky then getting 5 total rows when the userid exists would be okay also.
I hope this is clear enough, it was rather difficult to articulate.
How would I go about modifying the query to ensure the results are as described.
Many thanks.
You can order result by condition like ORDER BY (ID = "auth_user_id") DESC

How to manage user access and user permissions

I am working on an application with PHP + MySql. In my application I have a table for users, a table for relationships (friends, following, subscribed) and a table for posts. The main actions for users are:
A user has friends
A user can make post entries
A user can see the friends entries
And finally a user can block entries viewing for specific friends
If user A is friends with user B, then user A can see all entries from user B. But user B can restrict access to only a few friends for example. Now the query is: how can I manage these permissions? I was thinking of a table that stores each user that is blocked for viewing an specific entry, but this would't be a good idea once a single user can have several friends. So, how can I solve this? Can someone show me how to start? Maybe the right terms for searching on Google or a link for something similar.
You are on the right track. You are going to want to use linked tables. You would start with a table users. Each user has an id. Then create a table users_friends. This table would consist of two ids, user_id and friend_id. The last table would be users_restricted which would also consist of two ids, user_id and restricted_id.
For example
users
user_id name
1 user1
2 user2
3 user3
users_friends
friend1_id friend2_id
1 2
2 3
This says user 1 and 2 are friends and users 2 and 3 are friends. (This assumes that if user 1 is friends with user 2 then user 2 is also friends with user 1)
users_restricted
user_id restricted_id
1 2
Now even though user 1 and user 2 are friends, user 2 is in the restricted list meaning don't allow user 2 to view user 1's entries.
You can see that tables are linked via ids and all the ids come from the users table. This can be expanded to relate to entries as well. Just refer to entries by their id.
To have users blocked for specific entries you would have the following tables.
entries
entry_id user_id ... other columns holding entry information
1 1
2 1
3 2
4 2
Now user 1 has made 2 entries (entry 1 and entry 2) and user 2 has made 2 entries (entry 3 and entry 4). Another table would hold the restrictions.
entries_restricted
entry_id restricted_user_id
1 2
This would say user 2 cannot view entry 1.
To get the entries visible to user 2 your statement would look something like this.
SELECT e.*, er.entry_id FROM entries e JOIN entries_restricted er ON e.entry_id=er.entry_id WHERE er.restricted_user_id != 2;
The statement selects all the entry information excluding entries restricted to user 2.
You can start using following tables.
The first table is users table (as Jason.Wolfsmith suggested)
users
u_user_id u_name
1 user1
2 user2
3 user3
The second table can be like this.
friends_permissions
f_user_id f_friend_id permission entries
1 2 1 entry1
2 3 0
1 3 1 entry3
This table will contain permission and name of entries that should be allow for view. 1 - restrict some entries; 0 - allow all.
In the column permission data type might be set as SET('1','0') and data type in entries NULL.
Thus, user1 don't allow to view entry1 to user2. (entry1 and entry3 are from entries table).

Who's Online Database

I have a table that contains a Session ID, user ID, and Last Activity field.
Each time a user accesses the website, their session ID is inserted into the database.
If a Session ID is present, but User ID is set to 0, then the user is marked as a guest.
If a Session ID is present, and the User ID field is not 0, then the user is marked as a registered online users
My Question:
What's the best way to display the total users online, and split this information up in to how many are guests, and how many are registered? Can this be done with one query?
Example: There are currently xxx users online. xxx are registered, and xxx are guests.
Many Thanks,
FishSword
EDIT:
My session MySQL table contains the following fields:
sid - Stores the session ID.
user - Stores the user id of a logged in user. 0 is stored if the user is a guest.
ip - Stores the ip address of the user.
updated - stores a timestamp of when the user was last active.
Example Data:
See example data below. sud, user, ip, updated
sd456asdfas65asf465, 0, 192.168.128.33, 1315181434
v654xc654v65xc4v65z, 24, 192.168.128.65, 1315181529
dfsddas654g4sa6g4s6, 0, 192.168.128.33, 1315203155
y4g4df65gv4ff6sd54g, 69, 192.168.128.76, 1315181134
c4cs546sd654sdf654df, 42, 192.168.128.85, 1315181101
if465fsdf465sd46z65, 24, 192.168.128.65, 1315203144
dasd645as46d5a46465, 69, 192.168.128.12, 1315181134
Example 1 and 3 should only be logged once (as one guest online), as they have the same user id, and have came from the same computer/ip address.
Example 2 and 6 should only be logged once (as one member online), as they have the same user id, and have came from the same computer/ip address.
Even though example 4 and 7 have came from a different computer, user 69 should only be logged as once (one member online), as they have the same user id, and have came from the same computer/ip address.
Cheers! ;)
Make table
ID | SessID | Guest
1 | someRand | 1
2 | someRand2 | 0
And select it like
SELECT (SELECT COUNT(1) FROM sessions WHERE Guest = 1) as guests, (SELECT COUNT(1) FROM sessions WHERE Guest = 0) as users
and show it like
<?php
$result = mysql_query("SELECT (SELECT COUNT(1) FROM sessions WHERE Guest = 1) as guests, (SELECT COUNT(1) FROM sessions WHERE Guest = 0) as users");
$row = mysql_fetch_assoc($row);
echo "There are ".($row['users'] + $row['guests'])." users online, ".$row['users']." registered and ".$row['guests']." are guests";
SELECT COUNT(*) AS online,IFNULL(SUM(user_id=0),0) AS guests,IFNULL(SUM(user_id>0),0) AS registered FROM (
SELECT DISTINCT ip_address,user_id FROM sessions
) x
Create a table (recommended) or in user table where to store a last action timestamp column.
user_id | action_timestamp |
------------------------------
1 | 2011-08-15 13:02:00 |
2 | 2011-08-15 12:34:00 |
3 | 2011-08-15 11:05:00 |
Then to pull last online users for interval you make following select:
SELECT COUNT(*) FROM table AS t WHERE TIMEDIFF(NOW(), action_timestamp) < '00:15:00' /* fifteen minutes */
Now you have a count of online users in the last 15 minutes.
This will decrease overall performance (depending on the request and records), because every time the user makes a request you have to set two queries, one to insert/update record, and one for displaying the stats bellow.
You may combine the two queries into one multi-query to compensate a little bit.

Rating System in PHP and MySQL

If we look at the stackoverflow website we have votes. But the question is what is the bestway to store who has voted and who has not. Lets also simplify this even more and say that we can only vote Up, and we can only Remove the Up vote.
I was thinking having the table to be in such form
question - Id(INT) | userId(INT) | title(TEXT) | vote(INT) | ratedBy(TEXT)
Thre rest is self explanitory but ratedBy is a Comma Seperated Id values of the Users.
I was thinking to read the ratedBy and compare it with the userId of the current logged in User. If he dosent exist in the ratedBy he can vote Up, otherwise he can remove his vote. Which in turn will remove the value from ratedBy
I think to make another table "vote" is better. The relationship between users and votes is n to n, therefore a new table should be created. It should be something like this:
question id (int) | user id (int) | permanent (bool) | timestamp (datetime)
Permanent field can be used to make votes stay after a given time, as SO does.
Other fields may be added according to desired features.
As each row will take at least 16B, you can have up to 250M rows in the table before the table uses 4GB (fat32 limit if there is one archive per table, which is the case for MyISAM and InnoDB).
Also, as Matthew Scharley points out in a comment, don't load all votes at once into memory (as fetching all the table in a resultset). You can always use LIMIT clause to narrow your query results.
A new table:
Article ID | User ID | Rating
Where Article ID and User ID make up the composite key, and rating would be 1, indicating upvote, -1 for a downvote and 0 for a removed vote (or just remove the row).
I believe your design won't be able to scale for large numbers of voters.
The typical thing to do is to create to tables
Table 1: question - Id(INT) | userId(INT) | title(TEXT)
Table 2: question - ID(INT) | vote(INT) | ratedBy(TEXT)
Then you can count the votes with a query like this:
SELECT t1.question_Id, t1.userId, t1.title, t2.sum(vote)
FROM table1 t1
LEFT JOIN table2 t2 ON t1.question_id = t2.question_id

Categories