我正在创建一个脚本,用于搜索数据库并查找处于Realtors纬度和经度边界范围内的客户。如果客户纬度和长坐标在房地产经纪人的纬度和长边界范围内,则此脚本将仅通过电子邮件发送该客户范围内的房地产经纪人。我正在使用CRON作业来运行php脚本。我得到了脚本,通过电子邮件发送给房地产经纪人范围内的每个人,但当第三个房地产经纪人进入数据库时,即使纬度和长度超出范围,电子邮件也会转到第三个房地产经纪人。
如果客户端位于该房地产经纪人的范围内,并且仅向Realtor 发送电子邮件,则如何编写更好循环,其中每行都会被检查?感谢。
这是我的SQL代码。
CREATE TABLE `realtors` (
`rid` int(11) NOT NULL AUTO_INCREMENT,
`rEmail` varchar(255) NOT NULL,
`rZipCode` int(10) NOT NULL,
`rDist` int(11) NOT NULL,
`rlatitude` numeric(30,15) NOT NULL,
`rlongitude` numeric(30,15) NOT NULL,
PRIMARY KEY (`rid`)
) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8;
CREATE TABLE `customers` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`eMail` varchar(255) NOT NULL,
`zipCode` int(11) NOT NULL,
`clatitude` numeric(30,15) NOT NULL,
`clongitude` numeric(30,15) NOT NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8;
这是我的PHP代码。
<?php
use geocodeloc\GeoLocation as GeoLocation;
require_once 'geocodeloc/GeoLocation.php';
//require_once 'phpmailer/PHPMailerAutoload.php';
$db = getDB();
//database prep for customers
$cust = $db->prepare("SELECT fullName, eMail, clatitude, clongitude FROM customers ORDER BY id DESC");
$cust->bindParam("fullName", $fullName,PDO::PARAM_STR);
$cust->bindParam("zipCode", $zipCode,PDO::PARAM_STR);
$cust->bindParam("eMail", $email,PDO::PARAM_STR);
$cust->bindParam("clatitude", $clatitude,PDO::PARAM_STR);
$cust->bindParam("clongitude", $clongitude,PDO::PARAM_STR);
$cust->execute();
$cust->rowCount();
//database prep for realtors
$realt = $db->prepare("SELECT rEmail, rDist, rlatitude, rlongitude FROM realtors ORDER BY rid DESC");
$realt->bindParam("rZipCode", $rZipCode,PDO::PARAM_STR);
$realt->bindParam("rEmail", $rEmail,PDO::PARAM_STR);
$realt->bindParam("rDist", $rDist,PDO::PARAM_STR);
$realt->bindParam("rlatitude", $rlatitude,PDO::PARAM_STR);
$realt->bindParam("rlongitude", $rlongitude,PDO::PARAM_STR);
$realt->execute();
$realt->rowCount();
$i = -1;
while ($realtor_row = $realt ->fetch(PDO::FETCH_ASSOC) AND $customers_row = $cust ->fetch(PDO::FETCH_ASSOC)) {
$i++;
$realtLatLong = GeoLocation::fromDegrees( $realtor_row['rlatitude'], $realtor_row['rlongitude']);
$coordinates = $realtLatLong->boundingCoordinates($realtor_row['rDist'], 'miles');
//look to see if customers latitude and longitude is within range of the realtors lat and long boundaries.
if($customers_row['clatitude'] && $customers_row['clongitude'] <= $coordinates){
//email the realtor
// the message
$msgBody = "This is a test";
// use wordwrap() if lines are longer than 70 characters
$msgBody = wordwrap($msgBody,70);
$Mailto = $realtor_row['rEmail'];
$FromName = $customers_row['fullName'];
// send email
mail($Mailto, $FromName , $msgBody);
}else{
//send to debug log
}
};
?>
答案 0 :(得分:2)
循环遍历整个结果集并进行计算将很快杀死您的数据库。循环通过一个表,然后循环通过另一个表进行距离比较将更快地杀死您的数据库。幸运的是,这是车轮的重新发明。 Mysql通过ST_Distance
为此内置了功能SELECT * FROM realtors INNER JOIN customers WHERE ST_within(customers.loc, realtors.loc) < 10; /* location in degrees */
其中一度大约111公里。您需要按照以下方式更改表格
CREATE TABLE `realtors` (
`rid` int(11) NOT NULL AUTO_INCREMENT,
`rEmail` varchar(255) NOT NULL,
`rZipCode` int(10) NOT NULL,
`rDist` int(11) NOT NULL,
`loc` point NOT NULL,
PRIMARY KEY (`rid`)
) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8;
CREATE TABLE `customers` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`eMail` varchar(255) NOT NULL,
`zipCode` int(11) NOT NULL,
`loc` POINT not null,
PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8;
当然这需要mysql 5.7
使用空间数据类型意味着您可以使用索引进行空间查找。在RDBS中,如果表包含N行,则具有indes意味着您无需检查所有这N行以查找结果。因此,在这里使用空间数据+索引,您可以避免在单独的列中使用lat,lng时可能具有的NxM时间复杂度。
答案 1 :(得分:0)
无论您编写代码的速度有多快,复杂性仍然是NxM。
您应该做的第一件事是在Customer和Realtor之间创建一个关系,即一个包含Customer.id和Realtor.id的表。第一次填充此表时进行点击(无需更改代码)。之后,您只需在每次添加客户或房地产经纪人时创建关系。
当您发送电子邮件时,您只需要查看关系表。