按最近的位置分组

时间:2014-12-17 14:48:07

标签: 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 postcode in this row)
`long` varchar (longitude of postcode in this row)

每个经销商可以有多个dealer_locs(位置)。我试图输出一张显示最近经销商的表格。

我有一个我写的函数(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

我的问题是我不知道如何写这个小组(甚至不认为这需要一个小组,或者如果这是正确的练习)。

4 个答案:

答案 0 :(得分:0)

试试这个:

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

答案 1 :(得分:0)

这应该这样做:

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

答案 2 :(得分:0)

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
LEFT JOIN `dealers` as d 
    on d.id = dl.id_dealer
WHERE d.type='Real'
GROUP BY D.ID, D.Name
ORDER BY distance asc

您只需要使用聚合(分钟)和按名称分组。这假定名称是唯一的,否则您需要按名称和ID进行分组(假设名称可能不同)或者您可以按ID分组并让mySQL的扩展组按句柄名称进行分组。 (假设默认启用它)

此外,在这里使用LEFT Join似乎很奇怪。 where子句否定它使LEFT加入INNER。

您需要所有Dealer_Locations还是仅需要'Real'?

当你要求LEFT外连接时,由于你的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

答案 3 :(得分:0)

如果你想为每个名字找到最近的经销商,我会将你已经拥有的东西包装到子查询中,并使用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;

请注意,我将订单移至外部以订购最终结果。我也想出了“远方”#39;而不是距离,以避免歧义。您可以更改列名称以适合您的需要。