php - How to reverse a math equation based on a condition? - php

I have a unique and specific situation.
I have a search that searches volleyball players' stats. Once it queries and gets all the data, it then runs this:
$priority_query = $wpdb->get_results("
SELECT MAX(CAST(value AS UNSIGNED))
FROM wp_bp_xprofile_data
WHERE field_id = $field->id
", ARRAY_N);
$field_max = $priority_query[0][0];
$priority_percentage = $field->priority / $priority_total;
$priority_rank = $priority_rank + round($priority_percentage * ($value_total/$field_max), 3);
}
$priority_rank = $priority_rank * 10;
That is to figure out the players ranking based of off the other players that are returned by the search. It works great. However, it essentially is all based on "bigger is better". So it gives a higher rank for height, jumping height. Stuff like that.
Now I've added two more search criteria that are based on speed (sprints). It's giving a higher rank to the slowest people because it's a greater number. I need it to be opposite (smaller is better) when one of the new fields is selected for the search.
I've tried all sorts of things, but can't figure it out. I tried changing the query from MAX to MIN, but the rankings went through the roof and were still showing the slowest as the best.
Does anybody know how I could do this? Any help would be greatly appreciated, this has been driving me crazy.
Thank you
EDIT:
I can't have negative numbers since the ranking it being displayed. Also, I can't have any static numbers since players can sign up whenever they want and add their stats which in turn modifies the search results.
A co-worker and I got it working just by switching thes around: $value_total/$field_max to $field_max/$value_total and SELECT MAX to SELECT MIN Then I added a conditional statement to figure it out properly.
A slight issue however is when you start mixing the two types of criteria together. It gets a little wonky, but still ranks in the proper order.

Related

Using levenshtein in MySQL search for one result

I am trying to do a search on my MySQL database to get the row that contains the most similar value to the one searched for.
Even if the closest result is very different, I'd still like to return it (Later on I do a string comparison and add the 'unknown' into the learning pool)
I would like to search my table 'responses' via the 'msg1' column and get one result, the one with the lowest levenshtein score, as in the one that is the most similar out of the whole column.
This sort of thing:
SELECT * FROM people WHERE levenshtein('$message', 'msg1') ORDER BY ??? LIMIT 1
I don't quite grasp the concept of levenshtein here, as you can see I am searching the whole table, sorting it by ??? (the function's score?) and then limiting it to one result.
I'd then like to set $reply to the value in column "reply" from this singular row that I get.
Help would be greatly appreciated, I can't find many examples of what I'm looking for. I may be doing this completely wrong, I'm not sure.
Thank you!
You would do:
SELECT p.*
FROM people p
ORDER BY levenshtein('$message', msg1) ASC
LIMIT 1;
If you want a threshold (to limit the number of rows for sorting, then use a WHERE clause. Otherwise, you just need ORDER BY.
Try this
SELECT * FROM people WHERE levenshtein('$message', 'msg1') <= 0

How to write pager effect in PHP

I'm sorry, I am a newbie in PHP. Now I want to learn how to write a pagination effect in PHP. I know there are many tutorials for this on the net. I searched it and have a reference to them. When I try it by myself and don't have a reference to other resources, though, I still don't know how to write a pagination effect with PHP.
Now, I want to know what's the basic and important thing of writing a pagination in PHP. If anyone could give me more details, thank you.
For this example, I will use MySQL because it's a popular database to use with PHP. The general principle applies to other databases, but the precise way you use SQL to achieve the results is different.
The essence of pagination is that you have a number records, say 105, and you only want to display a smaller, more manageable number of records at a time, say 10 of them. In order to do this, you need to know how to find out the total number of records, and you need to know how to select just a subset of the records.
First, find out how many records you have. For this, you use COUNT(*) to count the records in the table. If your table is called Users:
SELECT COUNT(*) FROM Users;
Since we said there are 105 records in the table, this will return the result 105. We said each page has 10 records, so figure out how many pages there are in total: 105 / 10 = 10.5; round up to 11 because the extra records after page 10 need their own page. So, there are 11 pages in total. Your web page will display controls that enable the user to select a page from 1 to 11.
Instead of fetching all the records, you will only fetch one page at a time. In MySQL you generally do this using the LIMIT keyword; this allows you to choose a range of records. LIMIT syntax works like this: LIMIT $SKIP, $COUNT, where $SKIP is the number of records in the result set to skip, and $COUNT is the number to return. (Actually, you will get up to $COUNT records, in case fewer are available.)
The user has requested page 6. This means that I need to skip 5 pages before the results I want to show. With pages of 10 records each, this means I will skip 5 * 10 records, i.e. 50 records. In other words, $SKIP = ($PAGE_NUMBER - 1) * $PAGE_SIZE. You query would look like this:
SELECT User_ID, UserName, City, State from Users LIMIT 50, 10;
This gives you records 51-60 of the table.
See the documentation to learn more about how LIMIT works:
http://dev.mysql.com/doc/refman/5.5/en/select.html
Now you have a single page of records. However, the numbering of the records is dependent on their ordering. The query above will give you unpredictable results because the ordering is undefined. (A database can return records in any order it chooses unless you command it to use a certain ordering.) Thus, to do pagination, you need to define the order of the records. Use ORDER BY to define the ordering:
SELECT User_ID, UserName, City, State from Users ORDER BY UserName LIMIT 50, 10;
This allows you to show different pages of results, and always know that when you show page 6, it contains the records that come after the ones on page 5 and before the ones on page 7.
(If your records don't have any natural ordering, you will have to define an arbitrary one to make this work correctly.)
I have avoided mentioning PHP at all in this answer because I don't think it's necessary to do so to explain pagination. Pagination is entirely a matter of handling data. If you understand this, I think you can go read the tutorials and they will make sense to you and then you can figure how to write the PHP to do this.
Get page number
Know how many items to display on each page.
Using mysql command "LIMIT", get the offset and select how many rows you want.
Want to use a class? http://net.tutsplus.com/tutorials/php/how-to-paginate-data-with-php/
Or just a plain script to modify? http://pastebin.com/J8nTk1q5
If you are new to PHP, then you need to learn more PHP or risk future confusion.

How to Structure a 'Click-to-Win' type Comptetition with a set amount of random prizes

I realize this might be a confusing question so I will try and explain further.
I have been tasked with creating a Facebook competition tab on our page for users to click on a box and to be given a random prize.
There is going to be a finite number of each prize and one major prize.
I am just thinking of the best way to structure and implement this.
All I can think of is a database table to store the prizes with id, name, value and number_available.
Then, when the user clicks the box, a random number is generated between the min and max id's of the table, look up the db row with that id and check if there are any available, if there are, print out the details for the prize. If there's not any of that prize available then keep going until we get a prize that's still in 'stock'.
I think that's not a bad way to do it but not efficient when it comes down to relying on there being some of a particular prize left. If for example there were only one or two prizes left it could take a while for the right random number to be generated for prizes that are left.
The other thing that is bothering me is the major prize. Should I leave it to chance and just let it be won fair and square as soon as that random number is generated or should there be some kind of weighting applied to it to stop it being won quickly (competition is going to run until the end of the month)?
Then, if yes, how should I apply some kind of weighting?
Surely you don't need to keep repeating the query?
Your query would be something like:
SELECT * FROM `prizes` WHERE `number_available`>0 ORDER BY RAND() LIMIT 1
Then after it pulls that prize out it'd update the table to set number_available to number_available-1:
UPDATE `prizes` SET `number_available`=`number_available`-1 WHERE `id`='ID'
In which case it wouldn't need to repeat? Once the number_available is 0 then it's not part of the query anymore.
If you implement it like you proposed, you have to be careful about running into an endless loop, as soon as there are no prices available.
You could do it like this:
<?php
$prices = array();
$result = mysql_query("SELECT * FROM prices WHERE stock > 0");
while($row = mysql_fetch_assoc($result))
{
$prices[] = array();
}
shuffle($prices);
$price = array_pop($prices);
mysql_query("UPDATE prices SET stock = stock - 1 WHERE id = " . $price['id'] . ";");
echo "Congratulations, you have won " . $price['name'];
?>
As for the weighting of the major price: That's really your or your company's choice, can't help you there...
if you would like to read on this

Row Number in Symfony Doctrine Query

I am storing data for lap times in a database, the data consists of a distance, time, average speed and max speed.
I am trying to display a leaderboard which shows the top ten people in whatever query you set (who has gone thr furthest in total, best average time etc). However, below the top ten I want to show the user who is logged ins position in the leaderboard. To do this I am trying to run the same query ordering my results and adding a ROW NUMBER to get the position.
I am using symfony 1.4 with the Doctrine ORM and I can't for the life of me figure out how to get row numbers in a query. I know you can do it in SQL like so:
SELECT full_name, ROW_NUMBER() OVER(ORDER BY distance) AS row_number
Yet I can't get it working in Doctrine Symfony.
Does anyone have any ideas on a way I can do this? (or even another way of going about it)
Thanks in advance.
Ok heres my solution:
I kind of found an answer to this after some more experimenting and collaborating.
What I did was get rid of the select and just return the ordered list of results;
$results = self::getInstance()->createQuery('r')
->orderBy('r.distance')
->execute();
Then I hydrated this result into an array and used array_search() to find the key of the result in the array (luckily I am returning user data here, and I know the user I am looking for in the array)
$index = array_search($user->toArray(), $results->toArray());
I can then return the $index + 1 to give me the users position in the leaderboard.
There is probably a better way to do this database side, but I couldn't for the life of me find out how.
If anyone has a better solution then please share.

Suggestion for a efficient Pagination tutorial?

I have looped data from mysql, and it's a pretty long list. What's the most efficient way to do pagination? Currently, I am looking at this one: http://www.evolt.org/node/19340
Feel free to recommend a better one, thanks !
Rather than fetching everything from the DB like in the article, you could just SELECT the rows you can actually display - ie. if you have 10 items per page, just select 10 - and then selecting the total amount of rows. If the DB is large this can be much more efficient even though it's two queries.
Like Sorin Mocanu said, if you want to order the result by some criteria, maybe modified time or some frequency, then sorting will be a big performance penalty. Even though you only need 10 records, you still need to sort all(maybe millions of) records, unless you make sure index is used and is used correctly.
Here is an excellent article regarding pagination with mysql:
http://www.percona.com/ppc2009/PPC2009_mysql_pagination.pdf
Or from mysql website:
http://dev.mysql.com/doc/refman/5.5/en/order-by-optimization.html
I've been using the example in the book Wicked Cool PHP as my starting point. Very neat and well explained IMO.
You want something like
SELECT * FROM your_table WHERE condition = true ORDER BY some_field LIMIT 100, 10
Where 100 is the number of records to skip and 10 is the number of rows to retrieve.
Make sure you have an index covering condition and the order criteria fields if you want to have the maximum performance.
This is a really nice function/class to have as part of your standard library. I would strongly recommend you roll your own along these lines:
Query to work out total items (rows).
Code to work out upper & lower limit based on number of items you want to display per page.
Second query LIMIT'ed accordingly.
I'd post some code, but that would take the fun out of it :)

Categories