Compare one query with multiple results in PHP - php

I have two text input. Like This:
So, I have some kind of dynamic ajax search. I pass the input data and make two different mysql select. Something like this:
Table finalmap - SELECT 1
id -------- latitud-----longitud---
1 | 6.2523915 | -75.5737028 |
2 | 6.2640349 | -75.5990783 |
3 | 6.2642411 | -75.5999791 |
4 | 6.2638461 | -75.5982590 |
-------------------------------------
Table finalmap - SELECT 2
id -------- latitud-----longitud---
6 | 6.262669 | -75.596799 |
7 | 6.258019 | -75.598001 |
8 | 6.253668 | -75.599374 |
9 | 6.250724 | -75.602335 |
-------------------------------------
So, I want to compare every single "latitud and longitud field" with all the "latitud" and "longitud" fields of the SELECT2:
I have this Php, I have to make some improvements but can say that it worked:
<?php
$buscar = $_POST['b'];
$buscarcarrera = $_POST['c'];
$whatIWant = substr($buscar, strpos($buscar, "Calle") + 5);
$whatIWant2 = substr($buscarcarrera, strpos($buscarcarrera, "Carrera") + 5);
$vacio = "Calle50A";
$vacioc = "Carrera50A";
if (preg_match('/[A-Za-z]/', $whatIWant))
{
buscar($buscar, "", $buscarcarrera, "");
}
else
{
buscar($buscar, $vacio, $buscarcarrera, $vacioc);
}
function buscar($b, $exclusion, $buscarcarrera, $exclusion2)
{
$con = mysql_connect('localhost', 'root', '');
mysql_select_db('map', $con);
$sql = mysql_query("SELECT * FROM finalmap WHERE calle LIKE '%" . $b . "%' AND calle not in ('$exclusion')", $con);
$contar = mysql_num_rows($sql);
if ($contar == 0)
{
echo "No se han encontrado resultados para '<b>" . $b . "</b>'.";
}
else
{
while ($row = mysql_fetch_array($sql))
{
$nombre = $row['calle'];
$id = $row['id'];
$lat = $row['latitud'];
$lon = $row['longitud'];
}
}
$sql2 = mysql_query("SELECT * FROM finalmap WHERE calle LIKE '%" . $buscarcarrera . "%' AND calle not in ('$exclusion2')", $con);
$contar2 = mysql_num_rows($sql2);
if ($contar2 == 0)
{
echo "No se han encontrado resultados para '<b>" . $b . "</b>'.";
}
else
{
while ($row2 = mysql_fetch_array($sql2))
{
$nombre2 = $row2['calle'];
$id2 = $row2['id'];
$lat2 = $row2['latitud'];
$lon2 = $row2['longitud'];
}
}
}
function distance($lat1, $lon1, $lat2, $lon2, $unit)
{
$theta = $lon1 - $lon2;
$dist = sin(deg2rad($lat1)) * sin(deg2rad($lat2)) + cos(deg2rad($lat1)) * cos(deg2rad($lat2)) * cos(deg2rad($theta));
$dist = acos($dist);
$dist = rad2deg($dist);
$miles = $dist * 60 * 1.1515;
$unit = strtoupper($unit);
if ($unit == "K")
{
return ($miles * 1.609344);
}
else
if ($unit == "N")
{
return ($miles * 0.8684);
}
else
{
return $miles;
}
}
echo distance(32.9697, -96.80322, 29.46786, -98.53506, "M") . " Miles<br />";
echo distance(32.9697, -96.80322, 29.46786, -98.53506, "K") . " Kilometers<br />";
echo distance(32.9697, -96.80322, 29.46786, -98.53506, "N") . " Nautical Miles<br />";
?>
Then: how could compare each of the values ​​using the function to determine the proximity between the coordinates (using my distance() function)?. My problem is I don't know how to compare distance between each point of the 1st query with each point of the 2nd query, with every possible combinations.
I want to have something like this function compare (lat1,lon1,lat2,lon2);
(lat1,lon1,lat3,lon3),(lat1,lon1,lat4,lon4),(lat1,lon1,lat5,lon5),(lat1,lon1,lat6,lon6) and so on.
Thank you very much in advance for any help given

Your logic is completely wrong and you are way complexifying what you are looking for. It s much simpler than you think.
First: in order to drastically speed up your script and queries as well as protecting it from any attacks, use PDO prepared statements and security protocols. Mysql none prepared statements are deprecated for more than a decade !!!
My experience (25 years of coding) shows me to never ever trust what s coming into your server so I am a little phobic about security....
This tutorial explains the first basic steps you need to do and explains you this script as it should be (copy past all codes as they are).
Note, Using a local IP address instead of Localhost will speed up mysql connections by 2 to 5 depending on dev platform (lamp,wamp etc...)
set execution parameters
ini_set('memory_limit', '64M'); // memory limit used by script
set_time_limit(0); // no time limit
Establish Your secured mysql connection
try {
$con = new PDO('mysql:host=127.0.0.1;dbname=map;charset=UTF8','root','password');
$con->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
} catch (PDOException $e) {
echo 'Connection failed: ' . $e->getMessage();
}
Establish a second level security protocol to check if it s really an ajax call
$isAjax = isset($_SERVER['HTTP_X_REQUESTED_WITH']) AND
strtolower($_SERVER['HTTP_X_REQUESTED_WITH']) === 'xmlhttprequest';
if (!$isAjax) {
$user_error = 'Access denied - not an AJAX request from allowed computer...';
trigger_error($user_error, E_USER_ERROR);
exit;
}
Second: Use the distance function INSIDE your mysql query in order to properly sort the results you are looking for. Please note the mysql distance used here is different from the one you are currently using (faster and more precise).
It will gives you the distance between reference points from table 1 and all others from Table 2 in km, ordered by distance (closest as first row).
We suppose you get your results from your ajax like this:
if($isAjax){
$param4 = '%' . $_POST['b']. '%'; // MYSQL LIKE bind param buscar
$param5 = '(' . $_POST['c'] . ')'; //MYSQL NOT IN bind param buscarcarrera
}
We suppose you get your results from first query as this (simplified):
$sql1_array = array(
array('id' => 1, 'Lati' => 6.2523915, 'Longi' => -75.5737028),
array('id' => 2, 'Lati' => 6.2640349, 'Longi' => -75.5990783)
);
(note: always use "lati" and "longi" to avoid collision with PHP function like "long")
Your prepared statement:
$sql2 = "SELECT *, ( 6371 * acos( cos(radians(?))
* cos(radians(Latitude)) * cos(radians(Longitude) - radians(?)) +
sin( radians(?) ) * sin(radians(Latitude)))) AS distance
FROM finalmap WHERE calle LIKE ? AND calle NOT IN ?
ORDER BY distance LIMIT 10";
$stmt = $con->prepare($sql2);
Third: Execute a loop with each query1 result to get the distances compared with table 2. In the loop, you bind your parameters to your prepared stmt. This will drastically speed up your queries as connection with database is persistent and the query is prepared with PDO (compiled and in memory).
foreach ($sql1_array as $key => $value) {
$stmt->bindParam(1, $value['Lati'], PDO::PARAM_INT);
$stmt->bindParam(2, $value['Longi'], PDO::PARAM_INT);
$stmt->bindParam(3, $value['Lati'], PDO::PARAM_INT);
$stmt->bindParam(4, $param4, PDO::PARAM_STR);
$stmt->bindParam(5, $param5, PDO::PARAM_STR);
$stmt->execute();
$count = $stmt->rowCount();
if ($count >= 1) {
$result = $stmt->fetchAll(PDO::FETCH_ASSOC);
}
}
/* $result ordered by distance */
|**************************************|
|field 0 | field 1 | field 2 | distance|
|**************************************|
| 1 | a1 | a2 | 0.00123 | 1 meters
| 2 | b1 | b2 | 0.01202 | 12 meters
| 3 | c1 | c2 | 0.23453 | 234 meters
| 4 | d1 | d2 | 1.58741 | 1km and 587 meters
|**************************************|
I think you are all set ! Enjoy.

You should do something like this :
function buscar($b, $exclusion, $buscarcarrera, $exclusion2)
{
$nombre1 = array();
$id1= array();
$lat1= array();
$lon1= array();
$nombre2 = array();
$id2= array();
$lat2= array();
$lon2= array();
$con = mysql_connect('localhost', 'root', '');
mysql_select_db('map', $con);
$sql = mysql_query("SELECT * FROM finalmap WHERE calle LIKE '%" . $b . "%' AND calle not in ('$exclusion')", $con);
$contar = mysql_num_rows($sql);
if ($contar == 0)
{
echo "No se han encontrado resultados para '<b>" . $b . "</b>'.";
} else {
while ($row = mysql_fetch_array($sql))
{
if(array_key_exists('calle',$row) && array_key_exists('id',$row) && array_key_exists('latitud',$row) && array_key_exists('longitud',$row)) {
// ignore data with a missing field
$nombre1[] = $row['calle'];
$id1[] = $row['id'];
$lat1[] = $row['latitud'];
$lon1[] = $row['longitud'];
}
}
}
$sql2 = mysql_query("SELECT * FROM finalmap WHERE calle LIKE '%" . $buscarcarrera . "%' AND calle not in ('$exclusion2')", $con);
$contar2 = mysql_num_rows($sql2);
if ($contar2 == 0)
{
echo "No se han encontrado resultados para '<b>" . $b . "</b>'.";
} else {
while ($row2 = mysql_fetch_array($sql2))
{
if(array_key_exists('calle',$row2) && array_key_exists('id',$row2) && array_key_exists('latitud',$row2) && array_key_exists('longitud',$row2)) {
// ignore data with a missing field
$nombre2[] = $row2['calle'];
$id2[] = $row2['id'];
$lat2[] = $row2['latitud'];
$lon2[] = $row2['longitud'];
}
}
}
$nbData1 = count($nombre1);
$nbData2 = count($nombre2);
if($nbData1 > 0 && $nbData2 > 0) {
// there are data in both 1st and 2nd query
$distances = array();
// loop on all data from 1st query
for($i1 = 0; $i1 < $nbData1; $i1++) {
// loop on all data from 2nd query
for($i2 = $i1; $i2 < $nbData2; $i2++) {
// storing result of the distance
$distances[] = array('i1' => $i1,
'i2' => $i2,
'dist' => array('M' => distance($lat1[$i1], $lon1[$i1], $lat2[$i2], $lon2[$i2], 'M'),
'K' => distance($lat1[$i1], $lon1[$i1], $lat2[$i2], $lon2[$i2], 'K'),
'N' => distance($lat1[$i1], $lon1[$i1], $lat2[$i2], $lon2[$i2], 'N')
)
)
}
}
}
foreach($distances as $distance) {
// use each result
$i1 = $distance['i1'];
$lat1 = $distance['lat1'];
$lon1 = $distance['lon1'];
$i2 = $distance['i1'];
$lat2 = $distance['lat2'];
$lon2 = $distance['lon2'];
$dist = $distance['dist'];
$distM = $dist['M'];
$distK = $dist['K'];
$distN = $dist['N'];
echo "Have fun with theses data !\n";
}
}
So, storing the content of your rows.
Then parse all your data, to calculate all possible distances.
Then use the result as you wish.

This is much better to process distance calculation in the 2nd query, and this is faster, so the distance() function not needed. Also it seems that your formula is not correct.
$buscar = $_POST['b'];
$buscarcarrera = $_POST['c'];
$whatIWant = substr($buscar, strpos($buscar, "Calle") + 5);
$whatIWant2 = substr($buscarcarrera, strpos($buscarcarrera, "Carrera") + 5);
$vacio = "Calle50A";
$vacioc = "Carrera50A";
if (preg_match('/[A-Za-z]/', $whatIWant))
{
buscar($buscar, "", $buscarcarrera, "");
}
else
{
buscar($buscar, $vacio, $buscarcarrera, $vacioc);
}
function buscar($b, $exclusion, $buscarcarrera, $exclusion2)
{
$con = mysql_connect('localhost', 'root', '');
mysql_select_db('map', $con);
$sql = mysql_query("SELECT * FROM finalmap WHERE calle LIKE '%" . $b . "%' AND calle not in ('$exclusion')", $con);
$contar = mysql_num_rows($sql);
if ($contar == 0)
{
echo "No se han encontrado resultados para '<b>" . $b . "</b>'.";
}
else
{
while ($row = mysql_fetch_array($sql))
{
$nombre = $row['calle'];
$id = $row['id'];
$lat = $row['latitud'];
$lon = $row['longitud'];
$dLat = '((latitud-'.$lat.')*PI()/180)';
$dLong = '((longitud-'.$lon.')*PI()/180)';
$a = '(sin('.$dLat.'/2) * sin('.$dLat.'/2) + cos('.$lat.'*pi()/180) * cos(map_coords_1*pi()/180) * sin('.$dLong.'/2) * sin('.$dLong.'/2))';
$sub_sql = '2*atan2(sqrt('.$a.'), sqrt(1-'.$a.'))';
$results = mysql_query(
"SELECT DISTINCT
id, calle, " . $sub_sql . " AS distance FROM finalmap
WHERE
calle LIKE '%" . $buscarcarrera . "%' AND calle not in ('$exclusion2')
ORDER BY
distance
", $con);
if ($results == 0)
{
echo "No se han encontrado resultados para '<b>" . $buscarcarrera . "</b>'.";
}
else
{
while ($row2 = mysql_fetch_array($results)) {
echo "Calle: " . $row2['calle'] . " Miles - " . $row2['distance']*3956;
echo "Calle: " . $row2['calle'] . " Kilometers - " . $row2['distance']*6367;
echo "Calle: " . $row2['calle'] . " Nautical Miles - " . $row2['distance']*3435;
}
}
}
}
}

I'm giving it a first try.
$output_array = array();
$i = 0;
while ($row = mysql_fetch_array($sql))
{
$j = 0;
while ($row2 = mysql_fetch_array($sql2))
{
$out_array[$i][$j][0] = $row2['latitud'] - $row['latitud']
$out_array[$i][$j][1] = $row2['longitud'] - $row['longitud']
++$j;
}
++$i;
}
print "<pre>";
print_r($out_array);
print "</pre>";
Preview (with random numbers) :
Array
(
[0] => Array
(
[0] => Array
(
[0] => 6
[1] => 9
)
[1] => Array
(
[0] => 6
[1] => 9
)
[2] => Array
(
[0] => 6
[1] => 9
)
............
............
............
Array[0][0][0] == difference between 1st result latitud(table 1) AND 1st result latitud(table 2)
Array[0][1][0] == difference latitud (1st res table1) AND (2nd res table2)
Same case for longitud.

I think cross join of table will do your work.
Let say first table is Table1 and second is Table2.
So the query:
Select Table1.id, Table1.latitud, Table1.longitude,
Table2.id, Table2.latitud, Table2.longitude
from
Table1 , Table2
This will give you all combination which you required.

I think that INNER JOIN will work. I'm just confused that you will provide the table-1 long and lat value or not.So I 'm writing both the options.Let's say first table is table1 and second is table2
When you will provide the lat and long value of table 1SELECT * FROM table1 AS t1 INNER JOIN table2 AS t2 ON t1.latitude=t2.latitud OR t2.longitude=t1.longitude WHERE t1.latitude='#enter the value#' AND t1.longitude='#enter the value#'
It will provide the filter result of the equal value in both tableSELECT * FROM table1 AS t1 INNER JOIN table2 AS t2 ON t1.latitude=t2.latitud OR t2.longitude=t1.longitude
Let me know if needs anything else.Thanking you.

You can easily generate the necessary result set in SQL without having to write a bunch of PHP code though.
It would also make thing a lot easier if you would actually show what you want your results to look like as a table. I'm confused as to what you're actually trying to do. My assumption is that you want to match the two queries when either the latitudes match exactly OR the longitudes match exactly.
Update: I found the SQL buried in your PHP code. Something like this should work:
"SELECT t1.latitud AS lat1, t1.longitud AS lon1,
t2.latitud AS lat2, t2.longitud AS lon2
FROM finalmap AS t1
INNER JOIN finalmap AS t2 ON t1.latitud=t2.latitud OR t1.longitud=t2.longitud
WHERE t1.calle LIKE '%" . $b . "%' AND t1.calle not in ('$exclusion')
AND t2.calle LIKE '%" . $buscarcarrera . "%' AND t2.calle NOT IN ('exclusion2');"
If you want all results from SELECT 1 even if there are no matches in SELECT 2 change the INNER JOIN to a LEFT JOIN.
I also noticed you're checking if fields have values after the query is returned. You can do those checks in the WHERE clause on the SQL query that way you don't get any results you don't actually want. It just depends on what a "no-value" looks like (NULL? empty string? etc.) as to how you would check that.

You can take Cartesian product of both tables so that you can find all possible combinations.
Otherwise, take two loops like
for(int i=0;i < n; i++)
for(int j=0; j< m; j++)
someProcess(a[i][0], a[i][1], b[j][0], b[j][1]);
And this will give you all possible combinations.
Your function should then have logic for geocoding/reverse geocoding to calculate distance.
I hope this helps!!

I'd support this answer, but add the other major point:
Fourth: do not use distance calculation and sorting with customly coded haversine formula neither in PHP, nor in MySQL. MySQL has spatial functions support for a long time. Moreover, when dealing with GIS it's better to move to PostgreSQL + PostGIS extension
Fifth: Utilize MySQL or any other RDBMS spatial indexes when sorting by distance. I doubt you can code anything more efficient with your "every-to-every distance comparison" approach.
Solution: review this answer and apply the following queries to your DB table:
ALTER TABLE `finalmap` ENGINE=MYISAM; -- changing your storage engine to MyISAM. It supports spatial indexes in MySQL
ALTER TABLE `finalmap` ADD `pt` POINT NOT NULL; -- adding POINT() spatial datatype for zip cetner. Eventually, you may remove the old lat/lng decimal columns
UPDATE `finalmap` SET `pt` = POINT(latitud,longitud);
ALTER TABLE `finalmap` ADD SPATIAL INDEX(`pt`);
Then, assuming you get a coordinates in input (let's say (6.25,-75.6)) that you need to compare to all records in your table and find the closest one, you need:
SELECT *, ST_Distance_Sphere(`pt`,POINT('6.25','-75.6')) as `dst`
FROM `fnialmap`
ORDER BY `dst`
LIMIT 1;
And, finally, sixth: please name your columns and variables in English. It may be so that someone else supports your code in the future and they have to deal with "latitud" and "longitud"

Related

SQL Server query returning no results in PHP, but runs fine in Management Studio

I have a rather large query that works fine in Microsoft SQL Server Management Studio. However when I try to run the same query in PHP, I'm getting no results. Here is my code, I know this is the worst way to connect to the database.
Public function GetClockedHours() {
$conn = odbc_connect('easydo', '', '');
if (!$conn) {
exit("Connection Failed: " . $conn);
}
$sql = "WITH ByDays AS ( -- Number the entry register in each day
SELECT
EventTm AS T,
CONVERT(VARCHAR(10),EventTm,102) AS Day,
FLOOR(CONVERT(FLOAT,EventTm)) DayNumber,
ROW_NUMBER() OVER(PARTITION BY FLOOR(CONVERT(FLOAT,EventTm)) ORDER BY EventTm) InDay
FROM CHINA_VISION_DorEvents
Where DorCtrls_Ref = '16' AND CardCode = '000006f1' AND CONVERT(Date,EventTm) > dateadd(day, -7, getdate())
)
,Diffs AS (
SELECT
E.Day,
E.T ET, O.T OT, O.T-E.T Diff,
DATEDIFF(S,E.T,O.T) DiffSeconds -- difference in seconds
FROM
(SELECT BE.T, BE.Day, BE.InDay
FROM ByDays BE
WHERE BE.InDay % 2 = 1) E -- Even rows
INNER JOIN
(SELECT BO.T, BO.Day, BO.InDay
FROM ByDays BO
WHERE BO.InDay % 2 = 0) O -- Odd rows
ON E.InDay + 1 = O.InDay -- Join rows (1,2), (3,4) and so on
AND E.Day = O.Day -- in the same day
)
SELECT Day,
SUM(DiffSeconds) Seconds,
CONVERT(VARCHAR(8),
(DATEADD(S, SUM(DiffSeconds), '1900-01-01T00:00:00')),
108) TotalHHMMSS -- The same, formatted as HH:MM:SS
FROM Diffs GROUP BY Day
ORDER BY Day desc";
$rs = odbc_exec($conn, $sql);
if (!$rs) {
exit("Error in SQL");
}
$array = array();
$i = 1;
while ($row = odbc_fetch_array($rs, $i)) {
foreach ($row AS $key => $value) {
$array[$i][$key] = $row[$key];
}
$i++;
}
var_dump($array);
return $array;
}
The expected result would be an array of results and the results would be:
Date Seconds hours
2015.01.27 18055 05:00:55
2015.01.26 33491 09:18:11
2015.01.23 32649 09:04:09
2015.01.22 31554 08:45:54
2015.01.21 31889 08:51:29
However what were are getting is an array of nothing.
How many results sets do you get back? If it's more than 1 then you need to pick the correct resultset:
bool odbc_next_result ( resource $result_id )
http://php.net/manual/en/function.odbc-next-result.php
I had this same problem. In my case I was executing like this
$sql = "SELECT * FROM table1";
$resultSet = odbc_exec($sqllink, $sql);
while ($data = odbc_fetch_array($resultSet)) {
$sql = "SELECT * FROM table2";
$resultSet2 = odbc_exec($sqllink, $sql);//failed here
while ($data2 = odbc_fetch_array($resultSet2)) {
//something here
}
}
and I changed like this and it worked
$sql = "SELECT * FROM table1";
$resultSet = odbc_exec($sqllink, $sql);
// Create an array and store the results
$queryResult = array();
while ($data = odbc_fetch_array($resultSet)) {
// push the required content into the array
$queryResult[$data['id']]['name'] = $data[name];
}
foreach($queryResult as $row) {
$sql = "SELECT * FROM table2";
$resultSet2 = odbc_exec($sqllink, $sql);
while ($data2 = odbc_fetch_array($resultSet2)) {
// something here
}
}

sort zip codes by distance

So, I'm working on a search form for my site. I've run into a road block. Seems others have too but I've been unable to find an answer for my question, at least one that I understand.
I found a PHP function online that grabs up all the zip codes within a specified radius. I edited the sql query so that I wasn't grabbing every zip code within that radius, but ones that are associated with a user account. The function works and grabs the zip codes I'm after. This function returns an array with the zip codes. I would like to sort the zip codes by distance from nearest to farthest, and apparently I'm no where near smart enough to figure out how to do it.
What I've Tried:
I found another PHP function that will calculate the distance between 2 sets of coordinates(lat,lon2, lat2, lon2). I created my own function that loops through my zip codes array and runs each zip through the calculateDistance function. Just seems to be a big mess. I believe I have all the pieces just not sure how to put it all together. Any help would be greatly appreciated.
Here is the zipcodeRadius function I'm using:
// get all the zipcodes within the specified radius - default 20
function zipcodeRadius($lat, $lon, $radius)
{
$radius = $radius ? $radius : 20;
$dbc = mysqli_connect(DB_HOST, DB_USER, DB_PASSWORD, DB_NAME);
$sql = 'SELECT DISTINCT zipcodes.ZIP,
members.*,
location.*
FROM members
LEFT JOIN location
ON members.id = location.user_id
LEFT JOIN zipcodes
ON location.zip = zipcodes.ZIP
WHERE activated="1"
AND (3958*3.1415926*sqrt((Latitude-'.$lat.')*(Latitude-'.$lat.') + cos(Latitude/57.29578)*cos('.$lat.'/57.29578)*(Longitude-'.$lon.')*(Longitude-'.$lon.'))/180) <= '.$radius.';';
$result = mysqli_query($dbc, $sql);
// get each result
$zipcodeList = array();
while($row = mysqli_fetch_array($result))
{
array_push($zipcodeList, $row['ZIP']);
}
return $zipcodeList;
}
Here is the calculateDistance function
function calculateDistance($latitude1, $longitude1, $latitude2, $longitude2) {
$theta = $longitude1 - $longitude2;
$miles = (sin(deg2rad($latitude1)) * sin(deg2rad($latitude2))) + (cos(deg2rad($latitude1)) * cos(deg2rad($latitude2)) * cos(deg2rad($theta)));
$miles = acos($miles);
$miles = rad2deg($miles);
$miles = $miles * 60 * 1.1515;
return $miles;
}
And, Here's my seemingly useless function:
$matches = join(',',$zipCodeArray);
function sort_zip_by_distance($matches, $lat, $lon){
$dbc = mysqli_connect(DB_HOST, DB_USER, DB_PASSWORD, DB_NAME);
$queryDistance = "SELECT * FROM zipcodes WHERE ZIP IN ($matches)";
$resultDistance = mysqli_query($dbc, $queryDistance)
or die("Unable to query the database");
while($rowDistance = mysqli_fetch_array($resultDistance)){
$miles = calculateDistance($lat, $lon, $rowDistance['Latitude'], $rowDistance['Longitude']);
echo '<p>ZIP: ' . $rowDistance['ZIP'] . ' | Lat: ' . $rowDistance['Latitude'] . ' | Lon: ' . $rowDistance['Longitude'] . ' | Miles: ' . $miles . '</p><br />';
$distanceTotal = array();
array_push($distanceTotal, $rowDistance['ZIP'], $miles);
}
return $distanceTotal;
}
You can do arbitrary math in order by clauses, but you'd most likely to actually RETURN the distances found, so why not do
SELECT *, long_ugly_distance_calc_here AS distance
...
ORDER BY distance DESC

PHP/MySQL ignoring digits to the right of the decimal point

I wrote a code that lets the user vote for one out of the two options and the score is calculated using a modified Elo rating system. However, digits to the right of the decimal point are ignored when I vote for either of the options. I added the floatval function but it didn't help.
$query = "SELECT pic,score,id FROM nfl
JOIN (SELECT r1.random_id
FROM nfl_map AS r1
JOIN (SELECT (RAND() *
(SELECT MAX(row_id)
FROM nfl_map)) AS row_id)
AS r2
WHERE r1.row_id >= r2.row_id
ORDER BY r1.row_id ASC
LIMIT 1) as rows ON (id = random_id)";
$query_2 = "SELECT pic,score,id FROM nfl
JOIN (SELECT r1.random_id
FROM nfl_map AS r1
JOIN (SELECT (RAND() *
(SELECT MAX(row_id)
FROM nfl_map)) AS row_id)
AS r2
WHERE r1.row_id >= r2.row_id
ORDER BY r1.row_id ASC
LIMIT 1) as rows ON (id = random_id)";
$res_2 = $mysqli->query($query_2);
if (!$res_2) die ("Result display failed: " . $mysqli->errno . " - " . $mysqli->error);
$pic_2 = $res_2->fetch_assoc();
$id_2 = $res_2->fetch_assoc();
$score_2 = $res_2->fetch_assoc();
$res_1 = $mysqli->query($query);
if (!$res_1) die ("Result display failed: " . $mysqli->errno . " - " . $mysqli->error);
$pic_1 = $res_1->fetch_assoc();
$id_1 = $res_1->fetch_assoc();
$score_1 = $res_1->fetch_assoc();
$Ra = $score_1;
$Rb = $score_2;
$calc_pow_1 = (($Rb - $Ra) / 400);
$calc_pow_2 = (($Ra - $Rb) / 400);
$float_calc_pow_1 = floatval($calc_pow_1);
$float_calc_pow_2 = floatval($calc_pow_2);
$Ea = 1 / (1 + pow(10,$float_calc_pow_1));
$Eb = 1 / (1 + pow(10,$float_calc_pow_2));
$float_Ea = floatval($Ea);
$float_Eb = floatval($Eb);
// if user votes for picture no. 1
if (isset($_POST['vote_1']) && isset($_POST['id']) && isset($_POST['score']))
{
$id = $_POST['id'];
/* $score = $_POST['score'];
$pic = $_POST['pic']; */
//$mod = 2 * $Eb;
$K = 4;
$float_mod_1 = floatval($K * (1 - $float_Ea));
$query = "UPDATE nfl SET score=?+$float_mod_1 WHERE id=?";
// $score_new = $_POST['score'] + $mod;
$score_new = $_POST['score'] + $float_mod_1;
$stmt = $mysqli->prepare($query);
$stmt->bind_param('di', $_POST['score'], $_POST['id']);
$stmt->execute();
if ($stmt->errno) {
echo "Vote failed: " . $stmt->error();
}
else echo "Vote succeeded! New score of $id_1 is $score_new!";
$stmt->close();
}
// fetch picture no. 2
//
// query to the database
/* $query_2 = "SELECT pic,score,id FROM nfl
JOIN (SELECT r1.random_id
FROM nfl_map AS r1
JOIN (SELECT (RAND() *
(SELECT MAX(row_id)
FROM nfl_map)) AS row_id)
AS r2
WHERE r1.row_id >= r2.row_id
ORDER BY r1.row_id ASC
LIMIT 1) as rows ON (id = random_id)";
$res_2 = $mysqli->query($query_2);
if (!$res_2) die ("Result display failed: " . $mysqli->errno . " - " . $mysqli->error);
$pic_2 = $res_2->fetch_assoc();
$id_2 = $res_2->fetch_assoc();
$score_2 = $res_2->fetch_assoc(); */
// if user votes for picture no. 2
if (isset($_POST['vote_2']) && isset($_POST['id']) && isset($_POST['score']))
{
$id = $_POST['id'];
/* $score = $_POST['score'];
$pic = $_POST['pic']; */
//$mod = 2 * $Ea;
$K = 4;
$float_mod_2 = floatval($K * (1 - $float_Eb));
$query = "UPDATE nfl SET score=?+$float_mod_2 WHERE id=?";
// $score_new = $_POST['score'] + $mod;
$score_new = $_POST['score'] + $float_mod_2;
/* $query = "UPDATE nfl SET score=?+1 WHERE id=?";
$score_new = $_POST['score'] + $mod; */
$stmt = $mysqli->prepare($query);
$stmt->bind_param('di', $_POST['score'], $_POST['id']);
$stmt->execute();
if ($stmt->errno) {
echo "Vote failed: " . $stmt->error();
}
else echo "Vote succeeded! New score of $id_2 is $score_new!";
$stmt->close();
}
Here is the full code, if you need to see it: http://snipt.org/vDhj2
The code handling the situation when the user votes for the second option is pretty much the same (except $Ea changes to $Eb etc.). The 'score' row's properties in MySQL are following:
float(8,3) not null
Thanks.
EDIT: I'm not getting the notice anymore.
I think you simply missed a declaration in your code:
$res_1 = $mysqli->query($query);
if (!$res_1) die ("Result display failed: " . $mysqli->errno . " - " . $mysqli->error);
$pic_1 = $res_1->fetch_assoc();
$id_1 = $res_1->fetch_assoc();
$score_1 = $res_1->fetch_assoc();
$Ra = $score_1;
$Rb = $score_2;
I cannot see $score_2 defined anywhere in the code above where you try to assign it's value to another variable.
Warnings are there for a reason - ignoring them is a bad idea as it will inevitably lead to an error in your code. in this case, you simply need to declare your variable before you assign it (even if it is si,ply $score_2=0; if that is to be the default value, but assign it nonetheless.
Since it's just a notice, does it matter? If so, what should I change
in my code?
incorrectly written code that throws an error needs to be fixed.
you cannot assign $Rb = $score_2 before you create the $score_2 variable -- that is an error. put them in the right order to solve that problem
Getting a notice in PHP isn't an ERROR obviously, it's just ugly and can burden your load...
the notice you're getting means that you're using a non-set variable, doing a var_dump(isset($score_2)) will result in bool(false), meaning that it wasn't set.
PHP is a dynamically typed language, meaning that you don't have to declare variables prior to using them, however - it's a good practise if you do, to avoid such notices which could result in errors you simply need to declare the variable prior to using it.
are you expecting a number?
initialize it so
$score_2 = 0;
or
$score_2 = null;
depends on your needs, if you fill it with null, don't forget to allow in mysql NULL values...
Okay I found it. It was a stupid mistake with fetch_assoc() etc. Here is the revised code: http://snipt.org/vEaj7

Rank points based off the highest number in a row

I have a table called "member_points", which is set up like this:
|----|-------|----------|------------------------|
| id | uid | points | last_loggedin |
|----|-------|----------|------------------------|
| 1 | 1 | 5075 | 2012-08-02 02:04:00 |
|----|-------|----------|------------------------|
| 2 | 2 | 2026 | 2012-08-04 02:15:02 |
|----|-------|----------|------------------------|
I have a function below. I want the function to echo or return the rank like "Ranked #1" or "Ranked #2", based on the number in the row "points".
function getTopRanks($id) {
$sql = "SELECT MAX(points) AS toppoints FROM member_points";
$r = mysql_query($sql);
if ( $r !== false && mysql_num_rows($r) > 0 ) {
while ( $a = mysql_fetch_assoc($r) ) {
$points = stripslashes($a['toppoints']);
return ''.$points.'';
}
}
}
Can someone help me make this possible?
I think you are going to ranking user on the basis of points.
For such type of problem, i suggest you to first rank user on DESC order. Then pickup desire value form row.
function getTopRanks($id) {
$sql = "SELECT uid FROM member_points ORDER BY points DESC ";
$r = mysql_query($sql);
if ( $r !== false && mysql_num_rows($r) > 0 ) {
while ( $a = mysql_fetch_assoc($r) ) {
$points = stripslashes($a['toppoints']);
return ''.$points.'';
}
}
}
this will solve your problem.:)
UPDATE AS YOUR REQUIREMENTS:
function getTopRanksUser($id) {
$userPos ="Ranked position is:";
$count = 0;
$sql = "SELECT uid FROM member_points ORDER BY points DESC ";
$r = mysql_query($sql);
if ( $r !== false && mysql_num_rows($r) > 0 ) {
while ( $a = mysql_fetch_assoc($r) ) {
$count = $count+1;
$userPosCount = $userPos+$count;
return $userPosCount;
}
}
}
there should be return userPos+count. because count is increases up number of rows in table and the string ranked position is always remains same.
this will give result. Your can change return string according to your requirements. :)
thanks.
In your mysql query use ORDER BY (http://dev.mysql.com/doc/refman/5.0/en/sorting-rows.html)
so your query would become
SELECT points FROM member_points ORDER BY points DESC
this will sort the results from the query by the amount of points. (DESC will make them descending and ASC will make the result ascending).
Here's what I use for my rankings ... this code also takes into account ties and displays correctly. Just change "username" and "points" to your appropriate column names in your db and set the db connection vars: $hostName $databaseNanme $username and $password for you connection.
Hope this helps!
$sql1 = "SET #rnk=0; SET #rank=0; SET #scount=0;";
$sql2 = "SELECT username, points, rank FROM
(
SELECT AA.*,BB.username, points
(#rnk:=#rnk+1) rnk,
(#rank:=IF(#scount=points,#rank,#rnk)) rank,
(#scount:=points) newscount
FROM
(
SELECT * FROM
(SELECT COUNT(1) scorecount,points
FROM users GROUP BY points
) AAA
ORDER BY points DESC
) AA LEFT JOIN users BB USING (points)) A;";
try {
$conn = new PDO('mysql:host='.$hostName.';dbname='.$databaseName, $username, $password);
$conn->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
$conn->query($sql1);
$data = $conn->query($sql2);
$standings = $data->fetchAll(PDO::FETCH_ASSOC);
} catch(PDOException $e) {
error_log( 'ERROR: ' . $e->getMessage() );
}
print_r($standings);

PHP / Mysql - ORDER BY When Using Temp Tables

I've been trying to get this to work using ORDER BY and LIMIT, but it will output everything that was put in. The ORDER BY and LIMIT does not seem to work:
$lat1 = 37.349418;
$lon1 = -121.896286;
$distance = 25;
$q = "SELECT * FROM cityname WHERE feature_class = 'A' OR feature_class = 'P'";
$r = mysql_query($q) or die(mysql_error());
while ($row = mysql_fetch_array($r)) {
$lat = trim($row["latitude"]);
$lon = trim($row["longitude"]);
$name = $row["name"];
$pop = $row["population"];
$miles = distance($lat, $lon, $lat1, $lon1, "m");
$milesrounded = round($miles, 2);
if ($miles < $distance) {
if ($pop > 0) {
$q2 = "CREATE TEMPORARY TABLE IF NOT EXISTS `templocation4` (
`cityname` varchar(75) NOT NULL,
`distance` double NOT NULL
) ENGINE=MyISAM DEFAULT CHARSET=latin1";
$r2 = mysql_query($q2) or die(mysql_error());
$q1 = "INSERT INTO templocation4 (cityname, distance) VALUES ('$name', '$milesrounded')";
$r1 = mysql_query($q1) or die(mysql_error());
$q3 = "SELECT MIN(distance) FROM templocation4 GROUP BY distance DESC LIMIT 10";
$r3 = mysql_query($q3) or die(mysql_error());
while ($row1 = mysql_fetch_array($r3)) {
echo $row1["cityname"];
echo " ";
echo $row1["distance"];
echo "<br>";
}
$q5 = "DROP TABLE templocation4";
$r5 = mysql_query($q5) or die(mysql_error());
}
}
}
The table cityname has > 250K entries and I'm trying to sort it down to the closest city name based on the latitude / longitude that a user has input.
Thanks.
There's an error here:
$q3 = "SELECT MIN(distance) FROM templocation4 GROUP BY distance DESC LIMIT 10";
$r3 = mysql_query($q3) or die(mysql_error());
while ($row1 = mysql_fetch_array($r3)) {
echo $row1["cityname"]; // Where is cityname defined???
echo " ";
echo $row1["distance"]; // Where is distance defined???
echo "<br>";
}
$r3 only has one result column (which you haven't given a name). Are you sure you are using the correct variable because there's no way that your code should work as you have posted it.
Also your variable naming is really awful. Use meaningful names instead of $q1, $q2, etc...
Please check with Logic once again. "GROUP BY distance" will return single records from list of concern records. For e.g. if there are 100 users at 10 miles distance, your query will fetch 1st record found for 10 miles. this will NOT return all 100 records.
$q1 = "INSERT INTO templocation4 (cityname, distance) VALUES ('$name', '$milesrounded')";
$r1 = mysql_query($q1) or die(mysql_error());
$q3 = "SELECT MIN(distance) FROM templocation4 GROUP BY distance DESC LIMIT 10";
$r3 = mysql_query($q3) or die(mysql_error());
Need to rework with your need and logic.
//determine distance function
function distance($lat, $lon, $lat1, $lon1, $unit) {
$theta = $lon - $lon1;
$dist = sin(deg2rad($lat)) * sin(deg2rad($lat1)) + cos(deg2rad($lat)) * cos(deg2rad($lat1)) * cos(deg2rad($theta));
$dist = acos($dist);
$dist = rad2deg($dist);
$miles = $dist * 60 * 1.1515;
$unit = strtoupper($unit);
if ($unit == "K") {
return ($miles * 1.609344);
} else if ($unit == "N") {
return ($miles * 0.8684);
} else {
return $miles;
}
}
//sample latitude for testing purposes
$lat1 = 37.349418;
//sample longitude for testing purposes
$lon1 = -121.896286;
//sample distance for testing purposes
$distance = 25;
//query to select only a or p feature class
$query = "SELECT * FROM cityname WHERE feature_class = 'A' OR feature_class = 'P'";
$result = mysql_query($query) or die(mysql_error());
//create the temporary table - if it does not exist
$createtemporarytablequery = "CREATE TEMPORARY TABLE IF NOT EXISTS `templocation4` (
`cityname` varchar(75) NOT NULL,
`distance` double NOT NULL
) ENGINE=MyISAM DEFAULT CHARSET=latin1";
$resultofcreatetemporarytablequery = mysql_query($createtemporarytablequery) or die(mysql_error());
while ($row = mysql_fetch_array($result)) {
//gets latitude of city in database
$lat = trim($row["latitude"]);
//gets longitude of city in database
$lon = trim($row["longitude"]);
//gets cityname
$name = $row["name"];
//gets population of aforementioned cityname
$pop = $row["population"];
//determines distance from sample latitude and longitude from the latitude and longitude of cities in the cityname database
$miles = distance($lat, $lon, $lat1, $lon1, "m");
//round the miles to the 2nd decimal place
$milesrounded = round($miles, 2);
//determine if the city meets the request
if ($miles < $distance) {
//make sure its a populated city
if ($pop > 0) {
//insert stuff into temporary table
$insertstuffintotemporarytable = "INSERT INTO templocation4 (cityname, distance) VALUES ('$name', '$milesrounded')";
$resultofinsertstuffintotemporarytable = mysql_query($insertstuffintotemporarytable) or die(mysql_error());
}
}
}
//retrieve the closest 10 cities from the temporary table
$retrieve10closestcities = "SELECT * FROM templocation4 GROUP BY distance ASC LIMIT 10";
$resultofretrieving10closestcities = mysql_query($retrieve10closestcities) or die(mysql_error());
//determine how many results there are
$numrows = mysql_num_rows($resultofretrieving10closestcities);
//are there more than 0 results?
if ($numrows > 0) {
//loops through array
while ($row1 = mysql_fetch_array($resultofretrieving10closestcities)) {
echo $row1["cityname"];
echo " ";
echo $row1["distance"];
echo "<br>";
}
} else {
//echos no results found
echo "No results found";
}
//drop temporary table
$droptable = "DROP TABLE templocation4";
$resultofdroptable = mysql_query($droptable) or die(mysql_error());
And the answer is:
San Jose 0.7
Buena Vista 2.24
Burbank 2.65
Santa Clara 3.25
Fruitdale 3.33
Alum Rock 3.97
East Foothills 4.85
Campbell 5.21
Seven Trees 5.41
Milpitas 5.48

Categories