Mysql Rank with a Where clause will be faster? - php

I've a database with 8.000.000 rows, with 2 columns 'id' and 'score', i know also the exact number of users with score=0 (that is near 4.000.000).
I've a ranking board in my webpage with the query:
"SELECT id, score FROM table ORDER BY score DESC LIMIT ".$num_rank.", 25"
$num_rank defines which page show, and it's 25 users per page.
The query works, and it show what it has to show but the problem is that the query is really slow.
The question is the next query may be faster?:
$num_users_score_0 = 4000123
if(score==0){
$num_rank=$num_rank-$num_users_score_0
query=**"SELECT id, score FROM table WHERE score = 0 ORDER BY score DESC LIMIT ".$num_rank.", 25"**
}else{
query=**"SELECT id, score FROM table WHERE score > 0 ORDER BY score DESC LIMIT ".$num_rank.", 25"**
}
All suggestions are appreciatted!
Thanks!!!

Yes, your queries will be faster, with one improvement to the first: the `order by is unnecessary:
query="SELECT id, score FROM table WHERE score = 0 LIMIT ".$num_rank.", 25"
ALso, this will be faster with an index on table(score, id). In fact, with this index, you may be able to use your original query.

Related

Mysql select last 20 rows, with while loop

I have 50+ rows and each have an id, how do i get the last 20 records and display each ones information with php.
Is the best way to use a loop? I want it to display the results quick and not miss any rows, is a loop the best way to go then?
This is the code that I have
$result = $mysqli_log->query("SELECT * FROM `$usern`");
while( $row = $result->fetch_array() ) {
$credit = $row['credit'];
echo $credit;
}
The MySQL query being executed doesn't specify any "order" to the rows; MySQL is free to return the rows in any order it chooses, so it's possible that the "last 20" rows on one run of the query might differ from the "last 20" rows on a second run.
(We do observe repeated behavior when the statement is re-executed; it usually takes some DML operations, the addition of an index, or an OPTIMIZE table statement, to actually get a change in the results returned... but the point is, there is no "last 20" rows in the table. In MySQL, it's just a set of rows.)
To specify a specific sequence of the rows, add an ORDER BY clause to the query. Assuming that you want to use the unique id column to order the rows, and you want the last 20 rows, and you want them returned in ascending id sequence:
SELECT t.*
FROM ( SELECT u.*
FROM `$usern` u
ORDER BY u.id DESC
LIMIT 20
) t
ORDER BY t.id
And, yes, processing rows "in a loop" in PHP, just like you demonstrate, is a normative pattern.
To limit the number of queries use Limit and order them desc by your ID
Select *
From `$usern`
Order By ID Desc
Limit 20
To Flip them back in the forward order you can use a derived table
Select *
From (Select ID, Test
From test
Order By ID Desc
Limit 3) d
Order By ID Asc
If you need the newest 20 records, you have to ORDER DESC the result set by ID and then LIMIT that set result to 20 records.
So you can
use something like this:
$result = $mysqli_log->query("SELECT * FROM `$usern` ORDER BY `ID` DESC LIMIT 20");
while( $row = $result->fetch_array() ) {
$credit = $row['credit'];
echo $credit;
}
Another good approach, if you are using associative keys like $row['credit'], is to use featch_assoc instead of featch_array (if your framework provides such a function)

Selecting Top 100 Largest Values In A Table Given Possible Duplicates

I have a table with the following structure - steamid, itemid, eventid, value , all just ints or big ints that log hourly data I insert. So a user most likely has multiple entries with the same steamids, itemids, and even values.
I'm trying to get the 100 top values - but the same item must not repeat.
What I have so far is
SELECT itemid,value,steamid
FROM $table
GROUP BY itemid
ORDER BY value DESC
LIMIT 0,100
Which gives me this data set (sample only here):
itemid value steamid
=================================================
599291414 66397 76561198032389066
779150329 62882 76561198001229760
773965297 51895 76561198014617403
332883551 43201 76561197992659494
333434836 40880 7656119799359013
However, this for some reason ignores the true largest value listed in the table. I'm not sure how else I can format this so that I can ignore duplicate entries with the same itemid and steamid. I don't think I can group by steamid because then it would ignore other items that could be associated with a steamid.
Here's the first few if I select without grouping.
itemid value steamid
=====================================
1011809265 753665 76561198010314894
376615188 101684 76561197989760193
478937438 83448 76561198010314894
478937438 83448 76561198010314894
376662587 72693 76561197989760193
376662587 72693 76561197989760193
599291414 66454 76561198032389066
599291414 66454 76561198032389066
599291414 66454 76561198032389066
Insight appreciated and I'll gladly answer any questions that may help in figuring this out.
Try
SELECT * FROM (
SELECT itemid,value,steamid FROM $table GROUP BY itemid ORDER BY value DESC
) as tbl1
GROUP BY itemid, value
LIMIT 0,100
This should unique itemid, but then give you only the single values.
Try Adding Distinct.
SELECT DISTINCT itemid, value, steamid
FROM $table
ORDER BY value DESC
LIMIT 0,100

select 3 rows from mysql table, then get each row's specific column

Select 3 rows from table1
Get a specific column data out of each row.
Then use that each column data obtained , to make a query again to get data from table2.
Store the data obtained in step 4 into a variable for each row.
Then put them in json array (table 1 , 3 rows + table 2's data(each of them).
I am building a rank table, it displays top 3 users with their rank name.
For example:
User1 has 2000 points , user 2 has 4000points , user 3 has 10k points , so the top 3 user is :
user 3 > user 2 > user 1
So , i want the php to go to 'users' table and get the top 3 members using this:
$query = mysql_query("SELECT * FROM users ORDER BY pts DESC LIMIT 3");
$rows = array();
while($r = mysql_fetch_assoc($query)) {
$rows[] = $r;
}
Table structure for 'user':
1.username(varchar)
2.pts(int)
After the rows are put into an array , how can i get 'points' for each of the row in that array.
Then go to 'rank' table to get their ranknames.
Table structure for 'rank':
1.rank(varchar)
2.pts(int)
Inside rank table there is 'pts' to let php choose compare which rank the user is at based on the points from each row of the array.
Normally i would use this if its only for 1 user , but for multiple users , im not sure:
$result = mysql_query("SELECT * FROM rank WHERE pts <= '$upts' ORDER BY pts DESC LIMIT 1")
or die(mysql_error());
Then after getting the rank for the top 3 users , php will now add the ranks to each of the user(row) in that array(of course , add it to the rank owner, not just simply place it in).
Then JSON encode it out.
How can i do this?
I am not sure if this is what you want. That is combine the two query into one query. Please take a look at http://sqlfiddle.com/#!2/ad419/8
SELECT user.username,user.pts,rank.rank
FROM user LEFT JOIN rank
ON user.pts <=rank.pts group by user.id
UPDATED:
For extracting top 3, could do as below;
SELECT user.username,user.pts,rank.rank
FROM user LEFT JOIN rank
ON user.pts <=rank.pts
GROUP BY user.id
ORDER BY pts DESC LIMIT 3
If i understand correctly, you need to get values from Rank and Users tables. In order to do that in just one query You need to add FK (Foreign Key) to the Rank table that points to a specific user in the Users table.
So you need to add userId to the Rank table and then you can run:
SELECT r.rank, u.points from users u,rank r where u.userId = r.userId
This is roughly what you need.
Not quite the answer to your exact question, but this might be of use to you: How to get rank using mysql query. And may even mean that you don't require a rank table. If this doesn't help, I'll check back later.
Use this query
$query = "SELECT
u.pts,
r.rank
FROM users as u
left join ranks as r
on r.pts = u .pts
ORDER BY pts DESC
LIMIT 3";
This will bring what you required without putting into an array
$rec = mysql_query($query);
$results = arrau();
while($row = mysql_fetch_row($rec)){
$results[] = $row;
}
echo json_encode($results);
It looks like what you're trying to do is retrieve the rank with the highest point requirement that the user actual meets, which isn't quite what everyone else is giving here. Fortunately it is easily possible to do this in a single query with a nice little trick:
SELECT
user.username,
SUBSTRING_INDEX(GROUP_CONCAT(rank.rank ORDER BY pts DESC),",",1) AS `rank`
FROM user
LEFT JOIN rank ON user.pts >= rank.pts
GROUP BY user.id
ORDER BY pts DESC
LIMIT 3
Basically what the second bit is doing is generating a list of all the ranks the user has achieved, ordering them by descending order of points and then selecting the first one.
If any of your rank names have commas in then there's another little tweak we need to add on, but I wouldn't have thought they would so I've left it out to keep things simple.

mysql search by title in last 100 records

My case is, when someone is posting to my news web data with 600k records,
they can create the same title which someone just posted in the last few hours with same subject.
data: sid|title|desc|timestamp|userid
Usually I use:
select sid from ".$prefix."_stories WHERE title = '".$subject."' limit 0,1
It searches all data for $subject then notice poster if have they have the same title.
I need a query which searches in the last 100 records.
I tried the following, but this did not work:
select sid from ".$prefix."_stories WHERE title = '".$subject."' and sid > MAX(sid)-100 limit 0,1
You can do this with a subquery that returns the last 100 sid. Note, I have omitted the PHP concatenations for brevity here.
SELECT
last100.sid
FROM
(
SELECT
sid,
title
FROM $prefix._stories
ORDER BY sid DESC LIMIT 100
) last100
WHERE
last100.title = '$subject'
Assuming that you have a primary key, incrementing by 1 with every record (which will put newest at the bottom), just do this:
SELECT sid, title
FROM ".$prefix."_stories
ORDER BY sid DESC
LIMIT 100
This will select the last 100 records
Good point by Michael in my comments... Edit to code and further comment:
Removing the where clause, this will select the last 100 records... Run a loop to check to see if the title or summary already exists:
while ($row = $result) {
if $subject = $row['title'] {
$duplicate = TRUE;
endwhile;
}
}
Just compare the resulting data. Thanks Michael
Sort by sid (descending, so newest entries come first) and limit results to 100:
$sql = "select t.sid from (select sid, title from ".$prefix."_stories ORDER BY sid DESC LIMIT 0,100) t WHERE title = '".$subject."';"
Be sure to chek $subject to avoid SQL Injection (better: Use prepared statements / PDO).

mysql select statement and limiting the number of records

I am coding a blog post kind of thing, where the author will post the article and it will be displayed in the front end, my problem starts for selecting the posts as i have to meet certain conditions for posting the news in the front end,
I have 4 fields in the database namely
title
pic_title
pic_brief
pic_detail
you guessed it right apart from the title table the rest of three will hold the path to the images in varchar datatype, which will be used to display as the post, the format of the front end is such that
a) there will be total of eight post
displaying in the front end (eight
entries from the database)
b) there will be three post on the top which will include the value from
the table title, pic_title and
pic_brief (total of 3 values)
c) and the rest five will contain just the title and pic_title
(excluding the three entries of top)
Please NOTE: i want the second query to exclude the top 3 record
which already exist in the top i.e
(first query = 3 post in descending
order, second query = 8 - first 3 = 5
post)
The Order of the Post i want is by id DESC
EDIT: I took the first query as
SELECT * FROM news ORDER BY id DESC LIMIT 3
Now if i take the same second query and try populating the values by desc order again the same records will be accessed
In simple words i want a query that will skip the last three records order by id DESC
How do i achieve this feat in PHP?
If you just want the SQL, here it is:
First query
SELECT * FROM `table` LIMIT 3
Second query
SELECT * FROM `table` LIMIT 3,5
(where table is the name of your table of course. Of course you may want to add some ORDER BY clause. To execute these queries in PHP, I suggest reading the manual. If you have any specific problems after doing so, then you can post a new question.
This is a situation where I'd likely opt to select all eight records at once - the less trips to the database, the better.
SELECT t.title,
t.pic_title,
t.pic_brief
FROM TABLE t
ORDER BY t.id DESC
LIMIT 8
...because the rest is just presentation:
$query = sprintf("SELECT t.title,
t.pic_title,
t.pic_brief
FROM TABLE t
ORDER BY t.id DESC
LIMIT 8");
// Perform Query
$result = mysql_query($query) or die( mysql_error() );
$rowcount = 1;
// Use result
while ($row = mysql_fetch_assoc($result)) {
if(rowcount <= 3) {
echo $row['title']
echo $row['pic_title']
echo $row['pic_brief']
} else {
echo $row['title']
echo $row['pic_title']
}
++$rowcount;
}
first query will be like this
"select title, pic_title , pic_brief from table_name order by post_id desc limit 0 , 3"
and rest of five will be
"select title, pic_title from table_name order by post_id desc limit 3 , 5"
second query will exclude the three results returned by first query...
If you want more perfection you can collect all three Ids returned by first query and can add NOT IN in second query.
"select title, pic_title from table_name where post_id not in (1,2,3) order by post_id desc limit 0 , 5";

Categories