Echo the variable of i in while - php

i try something like this :
function userrank($userid){
$sql = mysql_query("SELECT * FROM users ORDER BY atacs DESC");
$i = 1;
while ($row = mysql_fetch_assoc($sql)) {
if ($row['username'] == $userid) {
echo 'You are on ' . $i . ' in the general leaderbord';
}
}
}
On the leaderboard it shows me the rank correctly, but i want to show me on another page too , on the "youraccount" page , for this i try to make this function.
what is wrong ?

Basically what you're doing here is counting how many users have an atacs greater than or equal to $userid's atacs. Problems with this:
Terribly inefficient. Note the database retrieves and sends to your
while loop an entry for every user, even those who have an atacs
less than the $userid. All but one of these while loop iterations
does nothing by design. Lots of wasted time sending data from the
database to PHP, which doesn't even use it.
Pulls way more data back
than is necessary. You end up with every row for every user in
your entire users table - but your result is just a scalar number
( how many users with > score ).
Actually gives you wrong results
in the case that your score is tied with others'. In this case some
users with the same score may be counted as "above" the user, others
as "below the users".
Databases are good at iterating over data; it's
all "locally" accessible and the database engine can make many
optimizations if you can describe in SQL what you are trying to
accomplish. So instead of doing it that way, why not just do
everything in the database?
set #user_atacs = ( select atacs from users where id = 12 );
select count(*) +1 from users where atacs > #user_atacs;
I've mocked up the table here: http://sqlfiddle.com/#!2/ff9a86/3
This solution essentially just counts the number of users with a higher atacs than the current user. All users with the same score will get the same rank, and the next rank will be appropriately higher, so it doesn't suffer from any of your method's errors.
As a final note, the most appropriate way to do something like leaderboards is probably to precompute the leaderboard periodically and then use the results to show each user's position in the leaderboards, rather than trying to compute it on the fly for each user. But that's even farther out of scope :)

You have to increment $i. I'm Assuming that the leader board order is represented by the result of your query. So, if true, change your code as follows:
function userrank($userid){
$sql = mysql_query("SELECT * FROM users ORDER BY atacs DESC");
$i =0; // starts out with an unknown rank.
while ($row = mysql_fetch_assoc($sql)) {
$i++; // increment $i here.
if ($row['username'] == $userid) {
echo 'You are on ' . $i . ' in the general leaderbord';
}
}
}
The $i will increment for sure. So, if it is not working still, I'd look to see what the result of your query is. Try echoing $row['username'] and see what the value is and then compare that to the echoed calue of $userid.

Related

Need to return the name of person with maximum value from a column (fetched from database)

$sql = "SELECT firstname FROM candidate_info1 WHERE votes=(select MAX(votes) from candidate_info1";
$result = $conn->query($sql);
if ($result->num_rows > 0) {
// how do i echo the firstname of candidate with highest votes??
}
I'm new to PHP so please be gentle.
Here in the code I have to return the name of the person with maximum number of votes(stored in database candidate_info1), how do I do that?
What am I doing wrong?
Your query seems to be correct, since it:
returns the firstname
of the correct table
for the record(s) which match in vote number to the maximum vote number
However, if you need a single value, then you can use an order by desc, as suggested in other answers. If you want to return the firstname of all the records having the same vote number as the maximum, then order by desc is inadequate here.
Also, if your problem is that votes is not stored in this table, but rather in a different table, then you might need to find the groups having the maximum count from there, selecting the foreign key and then return the values in your main query using the in operator. Anyway, if you have a specific problem which was not mentioned here, then you will need to add the details.
You have to fetch record By
$person_name = $result->fetch_assoc($result);
$person_name = $person_name['firstname ']
while($row = $result->fetch_assoc()) {
$firstname=$row['firstname'];
}
echo $firstname;
In your query, you already return the name with the max votes so you just have to fetch the results in order to show that name.

PHP - Getting num_rows of different ID's without writing new statements?

Basically, I'm coding a site that has many different categories and I want to display the amount of rows specific to that ID.
So for example, I have as the query:
$query= "SELECT job_sec FROM jobs WHERE job_sec = ?";
mysqli_num_rows($query);
I need to know how I can count the rows of an ID then echo the rows counted.
I'd like the results to display:
Web Design: 2,001 jobs
Logo Design: 5,120 Jobs
The job_sec column just uses a numerical value, would it be easier to have a text value then count the rows relating to the text value and echo them?
I have a feeling I need to use an array however I need the most efficient method.
Any help would be much appreciated!
Assuming job_sec is the category and I think you are looking for "group by":
$sql= "SELECT job_sec, count(*) AS c FROM jobs GROUP BY job_sec";
$r = mysqli_query($sql);
while ($row = mysqli_fetch_assoc($r)) {
echo $row['job_sec'] . ': ' . $row['c'] . ' Jobs ';
}
(didn't test and not sure if the mysqli syntax is correct)

show row only 100 times PHP

How can I make a limit of showing the results? I need to limit it for 100 views.
In DB I have:
ID|NAME|PAGE|COUNT|DATE
In count I want to count untill 100 and then stop showing that ID. I could do it with count < 100. And then update the specific ID. I could get records with less than 100 views, but I couldn't manage to update count on the specific ID.
Row is showed with:
php code:
foreach($bannerGroups[0] as $ban) {
echo '<li class="right1">'.$ban->html().'</li>';
}
But I just don't know where to put the update in there. I tried, but all I got was to update only one ID. But it shows 4 on one page and randomizes them on refresh. So I don't know what to do.
Also I would like to say I am only learning php. Sorry for all the mess.
Code at http://pastebin.com/A9hJTPLE
If I understand correctly, you want to show all banners that have been previously-displayed less than 100 times?
If that's right, you can just add that to your WHERE clause:
$bannerResult = mysql_query("SELECT * FROM table WHERE page='cat' WHERE `COUNT` < 100");
To update them all, you can either run a query while displaying each individual banner, or "record" the id of each and run a single query at the end, like:
$ids = array();
foreach($bannerGroups[0] as $ban) {
$ids[] = $ban['ID']; // record the ID; don't know how Banner
// class works, assuming uses indexes; maybe ID() method?
echo '<li class="right1">'.$ban->html().'</li>';
}
...
mysql_query('UPDATE table SET `COUNT` = `COUNT` + 1 WHERE ID IN (' . join(',', $ids) . ')');
UPDATE:
Based off of a comment, your Banner class doesn't have a method to retrieve the individual banner's ID. In this case, you can record the ID values when you're building your banners array:
$ids = array();
while($row=mysql_fetch_assoc($bannerResult)) {
$banners[] = new Banner($row);
$ids[] = $row['ID']; // record the ID
}
// update the `count` on each record:
mysql_query('UPDATE table SET `COUNT` = `COUNT` + 1 WHERE ID IN (' . join(',', $ids) . ')');
sorry, but I got your question wrong...
first you have to insert a new sql-column like "viewcount" to the db...
on every read, you have to increment the value in viewcount...
for that behaviour (because, mysql does not allow sub-selects on update-clause on the same table), you have to fetch the results from db, as you do that, and pass all the primary-keys of the records to an array...
after the view-logic you have to fire up a query like:
UPDATE foo SET viewcount = viewcount + 1 WHERE id IN (1,2,3,4,5,6...,100);
where the IN-clause can be easily generated using your primary-keys-array with "implode(',', $arr);"
hope this helps.
$bannerResult = mysql_query("SELECT * FROM table WHERE page='cat' AND `count`<100");
#newfurniturey figured it out. in each foreach($banneruGroups added: $ids = $ban->getValue('id'); and then mysql_query("UPDATE dataa SET COUNT = COUNT + 1 WHERE id = '$ids'"); but is there any way to update them by adding query only once? And if the id is showed already 100 times i get Warning: Invalid argument supplied for foreach() in. Any idea how to fix it? I have 4 ids in DB . If one of them already have 100 views (count) then i get error!
Try to limit your data source for 100 items.
It's like OFFSET x LIMIT 100 in MySQL/PostgreSQL query or TOP 100 in MSSQL.

What is demonstrably better when paginating: storing result in $_SESSION or querying every page separately

Imagine I've got a database with lots of data, from which users can search.
The result of a typical search is generally around 20-100 rows, which are then paginated (20 rows per page).
I've thought of two approaches to handle the navigation for these pages and would like to know if there are any pros and/or cons to these and if there are any better alternatives.
Query once, store results in $_SESSION variable and filter rows according to current page. The reason I came up with this was to make the data retrieval once, without having to connect to the database for every page the user navigates. I don't know if it's better or worse than the other alternative I've come up with.
session_start();
$search = rawurldecode($_GET['search']); //search word
$interval = rawurldecode($_GET['interval']); //rows per page
$page = rawurldecode($_GET['page']); //page
$min_row = $interval * ($page-1)+1;
$max_row = $interval * $page;
//query if (no results stored or first page) && the current search is not the previous search
if((empty($_SESSION['SEARCH_RESULTS']) || $page == 1) && $_SESSION['SEARCH_RESULTS']['TERM'] != $search){
$_SESSION['SEARCH_RESULTS'] = array();
$_SESSION['SEARCH_RESULTS']['TERM'] = $search;
$query = "exec usp_Search '$search'";
$dbh = new DBH;
$dbh->Connect()->Query($query);
while($row = $dbh->Fetch_Array()){
$_SESSION['SEARCH_RESULTS']['ROWS'][] = $row;
}
}
for($j = 0; $j < count($_SESSION['SEARCH_RESULTS']['ROWS']); $j++){
$row = $_SESSION['SEARCH_RESULTS']['ROWS'][$j];
//ignore all other rows not on the page
if($j < ($min_row-1) || $j > $max_row) continue;
//print stuff
}
Query page by page. The query and the pagination is pretty straightforward.
//Query
$search = rawurldecode($_GET['search']);
$interval = rawurldecode($_GET['interval']);
$page = rawurldecode($_GET['page']);
$min_row = $interval * ($page-1)+1;
$max_row = $interval * $page;
$query = "exec usp_Search '$search', $min_row, $max_row";
$dbh = new DBH;
$dbh->Connect()->Query($query);
while($row = $dbh->Fetch_Array()){
//print stuff
}
SQL procedures from the alternatives
Is just a procedure with a SELECT query
SELECT
COL1,
COL2,
COL...
FROM TABLE1
WHERE (
COL1 LIKE '%'+#search+'%' OR
COL2 LIKE '%'+#search+'%' OR
COL... LIKE '%'+#search+'%'
)
Is a procedure that creates a temp table and then selects rows from variables start to end.
SELECT
COL1,
COL2,
COL...,
ROW_NUMBER() OVER (ORDER BY COL1) AS [ROW_NUMBER]
INTO #result
FROM TABLE1
WHERE (
COL1 LIKE '%'+#search+'%' OR
COL2 LIKE '%'+#search+'%' OR
COL... LIKE '%'+#search+'%'
)
SELECT
COL1,
COL2,
COL...
FROM #result
WHERE ROW_NUMBER BETWEEN #row_start AND #row_end
You really can't store all of the results in the _SESSION for at least a couple reasons:
Users may make multiple searches simultaneously
Search results may change between a user's page loads.
The second point depends on how frequently you update your DB, but is something to consider. The first is major, but you may also be able to get around it if you store the session in a clever way (but you don't want _SESSION getting too large either). This is irrespective of performance.
Another consideration about getting all results at once and storing into _SESSION is that the majority of your users may only make one search request per visit. I know you would like to think they will always look at all 100 results, but if a large chunk of those results are not even being used, you're wasting quite a lot just to save a query or two. It's up to you to figure out how your users navigate.
After reading that this is only going to be used by 20-30 people and only 70 rows a day, I'm satisfied to say you're wasting time trying to improve performance at this point. Go for the code that's easier to update later in case of major changes.
Consider this scenario:
User searches a term with 100 results stored in database.
You query the database once getting all 100 results and you store them in session.
User finds what he was looking for in the first 5 results and leaves the search page.
In the end, you "overheated" database to fetch 95 rows for nothing. What if those 100 results are 1000, or 10.000 ?
In my opinion, getting all the results in a single query and store the results in session is a "reliable method" to reduce performance.

Add Friends Function - friend already added

I have an application to add friends. I need to have my script to check, if the users' already friends. I thought I could do this by a COUNT. I did like this:
$username = $_GET[user];
$ven_til_id = $_SESSION['userID'];
$num = 1;
if(isset($_GET['add_friend'])){
$check=("SELECT username,ven_til_id, COUNT(*) AS num FROM friends WHERE username=$username AND ven_til_id=$ven_til_id GROUP BY username,ven_til_id")or die(mysql_error());
$result=mysql_query($check);
if(!$result){
echo "Cant run query.";
} else {
$num = mysql_num_rows($result);
}
if($num>0){
header("Location: /profil/$username?add_error");
} else {
$sql=mysql_query("INSERT INTO friends (username,ven_til_id)VALUES('$username', '$ven_til_id')")or die(mysql_error());
header("Location: /profil/$username");
}
}
?>
But when I'm adding one friend it's fine. It adds it and everything is fine. But then when I try to add another, it says we're already friends. I guess it's because it's counting how many times my ID (ven_til_id) is listed in the tables.
You're missing a comma:
SELECT
username,ven_til_id COUNT(*) AS num FROM ...
should be
SELECT
username,ven_til_id, COUNT(*) AS num FROM ...
Also, your reference to the count field is incorrect - it should be the third column or $row[2]
You may want to make your code more robust by referring to fields by name eg $row['num']
One final thing to confirm is that the value being retrieved with a count is being treated as an integer not a string. I don't think it's the problem here but you may want to explicitly cast it to avoid possible issues later eg...
$num = (int) $row[2];
Option 1
Just select the appropriate rows and see how many records you get back...
SELECT username,
ven_til_id
FROM friends
WHERE username=$username
AND ven_til_id=$ven_til_id
Then just count the number of records returned using PHP - eg mysql_num_rows() (I think that's the correct function name)
Clarification:
Change
$row = mysql_fetch_row($result);
$num = $row[2];
to
$num = mysql_num_rows($result);
Option 2
Get MySQL to do the counting for you - in qhich case you need to tell it to group multiple record together...
SELECT username,
ven_til_id,
COUNT(*) as Num
FROM friends
WHERE username=$username
AND ven_til_id=$ven_til_id
GROUP BY username,
ven_til_id
Then just read the 3rd value of the first row (num) and you'll have a count
NB: The second method may be overkill if you're only ever expecting a 1 or a 0

Categories