MySQL - Perl:如何在Perl示例中提交的“x”里面提交的“zipcode”中获取邮政编码数组

时间:2011-02-28 16:01:25

标签: mysql perl latitude-longitude zipcode

我在这里发现了很多计算,一些php的例子,大多数都是我的头脑。

我找到了这个例子:

SELECT b.zip_code, b.state,
       (3956 * (2 * ASIN(SQRT(
       POWER(SIN(((a.lat-b.lat)*0.017453293)/2),2) +
       COS(a.lat*0.017453293) *
       COS(b.lat*0.017453293) *
       POWER(SIN(((a.lng-b.lng)*0.017453293)/2),2))))) AS distance
FROM zips a, zips b
WHERE
       a.zip_code = '90210' ## I would use the users submitted value
GROUP BY distance
having distance <= 5; ## I would use the users submitted value

但是,我无法理解如何使用我的数据库实现查询。

看起来我的查询完全是我需要的。

然而,我甚至无法找到/理解b.zip_code实际上是什么! (最新b.zips a, zips b?)

我也不需要查询中的state

我的mySQL数据库结构是这样的:

    ZIP | LAT     | LONG
  33416 | 26.6654 | -80.0929

我写这篇文章是为了尝试返回某种结果(不是基于上面的查询)但是,它只会输出一个邮政编码。

## Just for a test BUT, in reality I desire to SELECT a zip code WHERE ZIP = the users submitted zip code
## not by a submitted lat lon. I left off the $connect var, assume it's there.
my $set1 = (26.6654 - 0.20);
my $set2 = (26.6654 + 0.20);
my $set3 = (-80.0929 - 0.143);
my $set4 = (-80.0929 + 0.143);
my $test123 = $connect->prepare(qq{SELECT `ZIP` FROM `POSTAL`
WHERE `LAT` >= ? AND `LAT` <= ? 
AND `LONG` >= ? AND `LONG` <= ?})  or die "$DBI::errstr";
$test123->execute("$set1","$set2","$set3","$set4") or die "$DBI::errstr";
my $cntr;
while(@zip = $test123->fetchrow_array()) {
    print qq~$zip[$cntr]~;
    push(@zips,$zip[$cntr]);
    $cntr++;
}

正如你所看到的,我是新手,所以我需要一些简单的解释。

因此,在Perl中,我如何从用户提交的邮政编码和用户提交的英里数DISTANCE中将邮政编码推送到数组中。可以是正方形而不是圆形,而不是对某个特征的批评。越快越好。

3 个答案:

答案 0 :(得分:5)

我将解决问题的一小部分但至关重要的部分:

  

然而,我甚至无法找到/理解b.zip_code实际上是什么! (什么是“b。”和“拉链a,拉链b”?)

基本上,查询连接两个表。但是,两个连接的表实际上都是相同的表 - “拉链”(换句话说,它将“拉链”表连接到自身“)。当然,因为查询的其余部分需要了解何时引用“zips”表的第一个副本以及何时到“zips”表的第二个副本,您为每个副本提供了表别名 - 即“a”和“b”。

因此,“b.xxx”表示“来自表拉链的列xxx,来自正在连接的该表的SECOND实例”。

答案 1 :(得分:3)

我没看到你的第一个查询出了什么问题。您的数据库中有纬度和经度(如果我理解,您将单个条目与所有其他条目进行比较)。您不需要提交或返回仅仅是示例的一部分的状态。使第一个查询的工作方式如下:

my $query = "SELECT b.zip_code,
       (3956 * (2 * ASIN(SQRT(
       POWER(SIN(((a.lat-b.lat)*0.017453293)/2),2) +
       COS(a.lat*0.017453293) *
       COS(b.lat*0.017453293) *
       POWER(SIN(((a.lng-b.lng)*0.017453293)/2),2))))) AS distance
FROM zips a, zips b WHERE
       a.zip_code = ? 
GROUP BY distance having distance <= ?";

my $sth = $dbh->prepare($query);
$sth->execute( $user_submitted_zip, $user_submitted_distance );
while( my ($zip, $distance) = $sth->fetchrow() ) ) {
     # do something
}

这不会那么快,但如果你有一个小记录集(少于30k行),它应该没问题。如果你真的想加快速度,你应该研究一下Sphinx这样的搜索引擎,它会为你做这件事。

答案 2 :(得分:0)

fetchrow_array返回列表引用列表,本质上是一个二维数组,其中每一行代表数据库查询的不同结果,每列代表查询中的一个字段(在您的情况下,只有每行一个字段或列。

当程序一遍又一遍地执行查询时,调用while ($test123->fetchrow_array())将导致无限循环。如果查询返回结果,则将满足while条件并且循环将重复。通常的习惯用语是更像for my $row ($test123->fetchrow_array()) { ...,它只会执行一次查询,然后遍历结果。

每个结果都是一个列表引用,您感兴趣的邮政编码位于第一个(也是唯一的)列中,因此您可以将结果累积在这样的数组中:

my @zips = ();    # for final results
for my $row ($test123->fetchrow_array()) {
    push @zips, $row->[0];
}

或者更简洁地使用Perl的map声明:

my @zips = map { $_->[0] } $test123->fetchrow_array()

做同样的事情。