MYSQL - fastest way to get points around coords [duplicate] - php

This question already has answers here:
MySQL Great Circle Distance (Haversine formula)
(9 answers)
Closed 6 years ago.
I'm trying to get points around "me" by location and it's pretty simple :
select * from X where ((SQRT(POW(69.1 * (a.lat - 49.201441 ), 2) +
POW(69.1 * (16.161299 - a.lng) * COS(a.lat / 57.3), 2))) <='1') LIMIT 5
*
my location = 49.201441;16.161299
distance = 1 (mile)
This query returns me 5 points around "me" at a distance of 1 mile. This is rly fast, but just when my table have a ... I don't know, maybe 5000 rows.
I'm using this query on 200 000 rows table, and it's very slow! Maybe .. 2-7 sec and even if the limit is 1 = no difference.
Can someone explain it to me and help me? Thanks a lot guys!
BTW: If my query does not contains this part of query = it takes maybe 0.0008s... so second part of query is correct.

I have used this for finding people near you.
table name: user_location
id|username|latitude|longitude
i am not sure that the distances is for a mile, but what this does is takes the users lat minus each persons from the database. If the users lat and long are within 1 it will be put into the results.
The biggest problem is 1 isn't equal to 1 mile. it is closer to 10miles i believe (it was a while ago and might not be 10 miles i can't remember), but you can always change this. Another problem is that you basically always have to update people's locations. Which isn't that bad, but if you have a slow server with a lot of users it can slow you down.
It is fast and works... Not the best solution, but might work for you. For me it atleast showed a nice surrounding area.
$query = "SELECT * FROM `user_location` WHERE (".$user_lat." - latitude) <= 1 AND (".$user_lon." - longitude) <= 1 LIMIT 100";
I tested this with 10,000 lines and it was just under 3 seconds with 254 people near me. (randomly generated content)

Related

how do i determine which questions to ask a user in a quiz based on previous answers

I have a list of questions in a category, and want to choose a subset of them to ask the user based on which ones they answered right/wrong previously.
I want to make it random, but in a way that the ones they have more trouble with are asked more frequently.
EDIT: I'm trying to figure out how to calculate the weight/bias/score for each question based on the number of times they've answered it right/wrong.
I came up with the following, but it seems odd to me:
I assign a score to each question based on how many times they answered it right/wrong
Obviously, if they've never been asked that question I need to assign an arbitrary score (I chose 5)
For all other question, I use the formula
score = wrong*2-right
so if I had the following 10 questions, the "score" would be calculated for each of them (R=# of times they got it right, W=# of times they got it wrong and S=score). From there, I take the lowest score and assign that a probability of 1 (in this case it was id=5 with a score of -7). I then take the difference between the lowest score and the second lowest score (id=1 with -5, a difference of 2) and assign it a probability of 1 + the difference = 3.
I continue this for every question, and then at the end I can just choose a random number between Min(1) and Max(82) and select the question that has the highest P where random < P. So if my random # was 79 I would choose id=2.
But this seems long and convoluted. Is there an easier way to do this (I'm using PHP and mysql, But I plan to do this within an app with a local datastore as well)
id R W S P
1 5 0 -5 3
2 3 5 7 82
3 6 2 -2 8
4 2 2 2 23
5 9 1 -7 1
6 3 1 -1 14
7 0 0 5 68
8 7 5 3 33
9 6 5 4 44
10 3 4 5 56
EDIT: to clarify, I'm stuck on the issue of "weight" (P value in my example)...I'm trying to find a good (and fast) way of calculating the "weight" for each problem, given the number of right and wrong answers they've given for the question
I am not sure if I understand your answer correctly but it seems you are looking for a sort of "weighted" random number generator. In essense what you want to do is give the problems they are having issues with more weight. Perhaps create a class called questions with a property of weight in it. That property can hold how much weight you put in it. Then when you select a random number generator use something like this.
http://codetheory.in/weighted-biased-random-number-generation-with-javascript-based-on-probability/
After doing some research, I realize that my initial method of calculating a weight is bit slow. After using the formula, I end up with some -ve weights. I then have to go through each one and add ABS(MIN(S)) to each weight, which is unnecessary.
My new formula would be S = CEILING(Wrong * 5 / Right)
Obviously I'd need to account for 0 values, so the code would be:
if (R == 0 AND W == 0) S = 10
else if (R == 0) S = W*5
else if (W == 0) S = CEILING(5/R)
else S = CEILING(W * 5 / R)
I've worked out the numbers for a few sample sets and this gives me fairly good results. It also allows me to keep the SCORE value updated in the database, so it doesn't need to be recalculated every time (just updated whenever that question is answered)
Once I have a set of 60 or so questions and I want to choose 5 or 10 of them, I can just create a random # between 1-SUM(SCORE) and then use a binary search to figure out which question that represents.
If anyone has a better suggestion for calculating the score/weight/bias or whatever it's called, I'd appreciate it.

PHP / SQL - Show specific number of rows per query

I apologize if this question has been asked already, I'm sure it has I just was not able to find a similar question/answer that solved my problem.
I am pulling data from PostgreSQL and I have an SQL statement similar to:
$SQL = "SELECT * FROM my_view_table WHERE id='".$my_id."'";
From this I run my query. The request pulls from a view in PostgreSQL which looks through more tables. That is correct. I'm not sure how to limit the number of rows to display. I receive about 1,000 rows of information with about 20 columns of data so it takes an incredible amount of time to query.
Is there a way to ask for rows 0 - 100, then 101 - 200, etc, so I can pull 100 at a time to display? I know I'll have to use a little code to keep track of the count, but I just need some SQL help with querying "x to y" rows.
Thank you for the help with this issue. (If there is another very similar question that has already been answered a link to that would be a sufficient answer!)
I've posted the answer to my question down below.
I found the answer to this question from gnarly's suggestion of LIMIT on SQL
$sql = "SELECT * FROM my_table LIMIT X OFFSET Y";
Where LIMIT only gives the X number of rows you want, and OFFSET gives the Y starting point. So showing rows 0 through 30:
$sql = "SELECT * FROM my_table LIMIT 30 OFFSET 0";
And showing rows 31 through 60:
$sql = "SELECT * FROM my_table LIMIT 30 OFFSET 30";

How to retrieve nearest data from mysql using GPS coordinates? [duplicate]

This question already has answers here:
PHP MySql and geolocation
(3 answers)
Closed 9 years ago.
I am using this SQL query to get data that is nearest to GPS coordinates.
SELECT geo_latitude, geo_longitude, geo_name, geo_country_code AS country,
(DEGREES(
ACOS(
SIN(RADIANS(47.470779)) * SIN(RADIANS(geo_latitude)) +
COS(RADIANS(47.470779)) * COS(RADIANS(geo_latitude)) *
COS(RADIANS(-87.890699 - geo_longitude))
)
) * 60 * 1.1515)
AS distance FROM `MyDatabase`.`allCountries` ORDER BY distance ASC LIMIT 20 ;
This query retrieves all the data irrespective of the distance. I would like it to display the data only within a radius of 10 miles. How can i achieve this?
There's two ways I've found. One way is to do a direct SQL query with a whole lot of math in the 'where' section, much like you've tagged for your AS distance section of the SQL. Essentially - conceptually - 'where distance < 10'
However, I've found that slows down my request ... so what I've done in addition is to pull out the square instead of the circle from the database. Simply put: figure out the 'ten miles west/north/east/south' coords, then put in WHERE geo_latitude < X1 AND geo_latitude > x2 AND geo_longitude < x3 AND geo_longitude > x4 to put a hard limit on what I get back. Then, if you really need to be that precise, cut off the corners by only displaying if( result.distance < 10 ){
Or to put it another way:
x1 = Coords + 10 miles north
x2 = Coords + 10 miles south
x3 = Coords + 10 miles east
x4 = Coords + 10 miles west
by whatever means you're using to indicate '10 miles north', and then use that to pull out a 'square' of 10-miles north, south, west, and east from the center point. As long as your geo_latitude and geo_longitude columns are indexed, this should be a fast database call.

SQL/PHP calculate percent of yes/no votes

This has me stumped I have Googled for ages now and have searched here but have had no joy on what is probably a very simple to do ...I dont know maybe im just searching with the wrong search terms i really dont know but heres my question ...
I have a basic voting script click yes vote goes up by 1, click no vote goes up by 1
SQL Table:
votes
id
item
yes
no
what i want to do is show the percent of wins (yes votes) over loses (no votes) rather then the actual number of votes so on the page rather then it saying
"Wins 400 loses 600"
it will calculate the percent between the yes and no and say:
"Wins 40% loses 60%"
as always thanks in advance for any help and assistance.
Update:
How can i get it to show at the moment i'm gettng "id #8 resource"
$query = "SELECT ((yes / (yes+no)) * 100) as yesPercent, ((no / (yes+no)) * 100) as noPercent FROM table WHERE id=1";
$result = mysql_query($query);
echo $result;
I assume its this line i got wrong (or probably the whole query *novice at work)
$result = mysql_query($query);
but have tried a few mysql_????() and none seem to work
As I understand it your table would hold
id - item - yes - no
1 - name - 400 - 600
Then you'd query
SELECT ((yes / (yes+no)) * 100) as yesPercent, ((no / (yes+no)) * 100) as noPercent FROM table WHERE id=1
It is very simple indeed.
You want to use this simple proportion
NumberYes : TotalVotes = Percentage : 100
And you can find percentage using the formula
Percentage = (NumberYes * 100) / TotalVotes

PHP&MySQL Store Distance Calculator - Postcodes

Right I have been trying to work out how to compare a given postcode to a database of say store addresses and have them ordered in terms of which one is closest to the given postcode (or ZIP code I guess).
This is mainly out of interest, rather than me asking you for advice and then selling it to a client :-O
First of all after research I discovered that you have to do distance with Lat/Long so I found an API that converts postcodes/zip codes to lat long and now my DB has a structure such as id, store_name, lat, long, postcode and I can convert a given postcode to a lat long.
But how in SQL do I make a query for the ones closest to a given lat long?
Try something like this:
// get all the zipcodes within the specified radius - default 20
function zipcodeRadius($lat, $lon, $radius)
{
$radius = $radius ? $radius : 20;
$sql = 'SELECT distinct(ZipCode) FROM zipcode WHERE (3958*3.1415926*sqrt((Latitude-'.$lat.')*(Latitude-'.$lat.') + cos(Latitude/57.29578)*cos('.$lat.'/57.29578)*(Longitude-'.$lon.')*(Longitude-'.$lon.'))/180) <= '.$radius.';';
$result = $this->db->query($sql);
// get each result
$zipcodeList = array();
while($row = $this->db->fetch_array($result))
{
array_push($zipcodeList, $row['ZipCode']);
}
return $zipcodeList;
}
UPDATE:
There is some discussion about efficiency. Here is a little benchmark for you with this query. I have a database that contains EVERY zipcode in the US. Some of them are duplicate because of the way zipcodes work (outside the scope of this topic). So I have just under 80k records. I ran a 20 mile radius distance on 90210:
SELECT distinct(ZipCode) FROM zipcodes WHERE (3958*3.1415926*sqrt((Latitude-34.09663010)*(Latitude-34.09663010) + cos(Latitude/57.29578)*cos(34.09663010/57.29578)*(Longitude- -118.41242981)*(Longitude- -118.41242981))/180) <= 20
I got back 366 total records and Query took 0.1770 sec. How much more efficient do you need?
check out this great open source project
Disclaimer: Not my project, and nor am I contributor. Purely a recommendation.
See this answer to a previous question for an example of calculating a bounding box before querying MySQL. This allows the complex formula in the MySQL query to run against a subset of the database entries, rather than against every entry in the table.

Categories