Mysql 按最近位置分组

Mysql 按最近位置分组,mysql,group-by,Mysql,Group By,我有以下表格结构: table `leads`: `id` int `postcode` varchar table `dealers`: `id` int `name` varchar table `dealer_locs`: `id` int `id_dealer` int (this is what links the loc to the dealer) `postcode` varchar `distance` int `lat` varchar (latitude of post

我有以下表格结构:

table `leads`:
`id` int
`postcode` varchar

table `dealers`:
`id` int
`name` varchar

table `dealer_locs`:
`id` int
`id_dealer` int (this is what links the loc to the dealer)
`postcode` varchar
`distance` int
`lat` varchar (latitude of postcode in this row)
`long` varchar (longitude of postcode in this row)
每个经销商可以有多个经销商位置。我试图输出一个表,显示距离潜在客户最近的经销商

我有一个我写的get_lat_long函数,它可以获取我想要的任何邮政编码的纬度和经度

考虑以下代码:

$lead['postcode'] = 'M6A 3A1';
$lat_long = get_lat_long($lead['postcode']);

$lat = $lat_long['lat'];
$long = $lat_long['long'];

$sql = mysql_query("select d.id, d.name,
                    (6371 * 3.1415926 * SQRT(($lat - dl.lat) * ($lat - dl.lat) + COS($lat / 57.2957795) * COS(dl.lat / 57.2957795) * ($long - dl.long) * ($long - dl.long)) / 180) as distance, 
                    dl.postcode as dl_postcode
                    from `dealer_locs` as dl
                    left join `dealers` as d on d.id = dl.id_dealer
                    where d.type='Real'
                    order by distance asc
                    ") or die(mysql_error());
现在此代码确实起作用,但由于每个经销商都有多个位置,因此显示的是重复代码

上述查询和代码的输出示例:

d.name        | distance
Joes Dealer   | 11
Kevins Dealer | 13
Mikes Dealer  | 21
Kevins Dealer | 43
Mikes Dealer  | 44
Joes Dealer   | 78
我想要的输出:

d.name        | distance
Joes Dealer   | 11
Kevins Dealer | 13
Mikes Dealer  | 21
我的问题是我不知道如何写这个小组,我甚至不认为这需要一个小组,或者这是否是正确的做法。

试试这个:

select 
    d.id, 
    d.name,
    (6371 * 3.1415926 * SQRT(($lat - dl.lat) * ($lat - dl.lat) + COS($lat / 57.2957795) * COS(dl.lat / 57.2957795) * ($long - dl.long) * ($long - dl.long)) / 180) as distance, 
    dl.postcode as dl_postcode
from `dealer_locs` as dl
left join `dealers` as d on d.id = dl.id_dealer
where d.type='Real' 
group by d.id 
order by distance asc
这应该做到:

select 
    d.id, -- you can take id from here if you want
    d.name,
    min(6371 * 3.1415926 * SQRT(($lat - dl.lat) * ($lat - dl.lat) + COS($lat / 57.2957795) * COS(dl.lat / 57.2957795) * ($long - dl.long) * ($long - dl.long)) / 180) as distance, 
    dl.postcode as dl_postcode
from `dealer_locs` as dl
left join `dealers` as d on d.id = dl.id_dealer
where d.type='Real'
group by d.id
order by distance asc
您只需要使用聚合min和按名称分组。不过,这假设名称是唯一的,否则您需要同时按名称和ID分组,假设名称可能不同,或者您可以只按ID分组,让mySQL的扩展组按句柄名称分组。假设已启用默认设置

此外,在这里使用左连接似乎很奇怪。where子句否定它,使左连接成为内部连接

您需要所有经销商的位置,还是只需要那些“真实”的位置

由于where子句的原因,当您请求左外部联接时

SELECT d.name,
   Min(6371 * 3.1415926 * SQRT(($lat - dl.lat) * ($lat - dl.lat) + COS($lat / 57.2957795) * COS(dl.lat / 57.2957795) * ($long - dl.long) * ($long - dl.long)) / 180)) as distance, 
   dl.postcode as dl_postcode
FROM `dealer_locs` as dl
INNER JOIN `dealers` as d 
    on d.id = dl.id_dealer
WHERE d.type='Real'
GROUP BY D.ID, D.Name
ORDER BY distance asc

如果您想为每个名称获取最近的经销商,我会将您已有的内容包装到子查询中,并在按名称分组时使用MIN函数获取最小距离,如下所示:

SELECT temp.name, MIN(temp.distance) AS distanceAway
FROM(SELECT d.id, d.name,
                (6371 * 3.1415926 * SQRT(($lat - dl.lat) * ($lat - dl.lat) + COS($lat / 57.2957795) * COS(dl.lat / 57.2957795) * ($long - dl.long) * ($long - dl.long)) / 180) AS distance, 
    dl.postcode AS dl_postcode
    FROM `dealer_locs` AS dl
    LEFT JOIN `dealers` AS d ON d.id = dl.id_dealer
    WHERE d.type = 'Real') temp
GROUP BY temp.name
ORDER BY distanceAway;

请注意,我将orderby移到了外部,以便对最终结果进行排序。为了避免模棱两可,我还提出了“distanceAway”而不是“distanceAway”。您可以根据需要更改列名称。

您可以使用DISTINCTname@AlwaysSunny这不仅仅是为了获得不同的名称,而是为了每个名称获得最近的经销商。顺便说一句,不要使用PHP不推荐的mysql\uAPI。请参阅PDO/mysqli和准备好的语句!内部查询没有任何优势。没有理由使用内部查询,也没有理由使用group by和order by Outside。我想没有,但这并不正确。这对我来说很有意义,因为OP已经有了一个工作结果集,所以我采取了操纵他的结果集的方法来得到他想要的。不过,这两种解决方案都可以。或者你可以只按id分组,mysql将为你做其余的事情,假设同一id没有不同的名称。那么你更愿意假设你不能有两个同名的人?为同一Id指定两个名称需要非常笨拙的数据库设计,这是由group by处理的。事实上,它不在select中,这意味着用户需要理解数据。这分离出了数据,事实上它没有呈现是由于OP所需的输出。我明白你的意思,但是假设有人根据你的查询调用了dealiers。在您正在介绍的用例中,用户可能会给同一个经销商打2次电话,但不知道是同一个经销商。即使有些人有多个名字,如果这很重要,你必须总是有办法选择一个作为默认名称。如果目的是检测错误数据,您还应该将Id带到无法工作的SELECT。group by将在结果集中的第一个距离处拾取一个值,您需要该值的最小值,或者在组之前强制执行顺序by@MiguelRoxo,这是一个很好的工作没有分钟。Mysql会做其他的事情。不,它不会,只有当你足够幸运,有足够的距离被订购时,它才会工作。如果你使用这个问题的数据,它已经是了,也许这就是为什么它对你有用you@DionSoft在QueryQueryWhat’s the point of the LEFT join中添加了注释?为什么不给where子句一个内部变量呢?另外,如果数据碰巧有两个不同的d.ID的d.name,会发生什么?没有,只是从原始查询继承了它。在这种情况下也不会有任何影响。事实上,mySQL group by extensions不会随机选择其中一个名称,并从具有不同名称的相同D.ID的查询结果中隐藏另一个名称。。。
SELECT temp.name, MIN(temp.distance) AS distanceAway
FROM(SELECT d.id, d.name,
                (6371 * 3.1415926 * SQRT(($lat - dl.lat) * ($lat - dl.lat) + COS($lat / 57.2957795) * COS(dl.lat / 57.2957795) * ($long - dl.long) * ($long - dl.long)) / 180) AS distance, 
    dl.postcode AS dl_postcode
    FROM `dealer_locs` AS dl
    LEFT JOIN `dealers` AS d ON d.id = dl.id_dealer
    WHERE d.type = 'Real') temp
GROUP BY temp.name
ORDER BY distanceAway;