我正在制作一个使用地理位置的网络应用程序,而我正在掀起一个“附近的地方”视图。这是非常简单的逻辑:它显示了存储在数据库中的最近5个位置。完美。
诀窍在于我希望它返回最近的5个地方或两英里内的所有地方,以较大者为准。换句话说,我希望用户能够在两英里内看到至少所有位置,但如果该半径内没有5个位置,我希望它们显示最近的5个
让我们将它们用于样本数据集。设置1:
| id | name | distance |
+----+----------------------+-----------+
| 3 | Earl of Sandwich | 0.3 |
| 4 | Nails 'n More | 0.8 |
| 22 | City Hotel | 1.7 |
| 5 | Mighty Medicine | 2.1 |
| 25 | Wonder Wings | 2.5 |
| 6 | Jean Warehouse | 2.7 |
| 9 | Ship Safe & Speedy | 2.9 |
| 2 | Bagel Bonus | 4.1 |
+----+----------------------+-----------+
设置2:
| id | name | distance |
+----+----------------------+-----------+
| 3 | Earl of Sandwich | 0.1 |
| 4 | Nails 'n More | 0.2 |
| 5 | Mighty Medicine | 0.5 |
| 6 | Jean Warehouse | 0.7 |
| 9 | Ship Safe & Speedy | 0.9 |
| 2 | Bagel Bonus | 1.2 |
| 22 | City Hotel | 1.7 |
| 25 | Wonder Wings | 2.1 |
+----+----------------------+-----------+
在第一组中,我想要返回第3,4,25,5和25行。在第二组中,我想要显示3,4,5,6,9,2和22.
我知道我总是可以将查询限制在100个地方,并通过PHP中的结果集进行过滤...但我想知道是否有更有效的方法在SQL中正确执行。
答案 0 :(得分:3)
总之,执行此操作的方法是运行两个查询并获取集合的UNION。而已。这样做的确很少有性能损失,因为如果结果中确实有超过5行,则已经需要第一组(可以产生> 5行)。
为了说明,我只使用同一个样本表中的2列,而不是使用2个数据集,查询将在下面进一步显示:
drop table if exists tbl1;
create table tbl1 (
id int,
name varchar(100),
distance1 float,
distance2 float
);
insert tbl1 values
( 3 , 'Earl of Sandwich ', 0.3, 0.1),
( 4 , 'Nails ''n More ', 0.8, 0.2),
( 22 , 'City Hotel ', 1.7, 1.7),
( 5 , 'Mighty Medicine ', 2.1, 0.5),
( 25 , 'Wonder Wings ', 2.5, 2.1),
( 6 , 'Jean Warehouse ', 2.7, 0.7),
( 9 , 'Ship Safe & Speedy ', 2.9, 0.9),
( 2 , 'Bagel Bonus ', 4.1, 1.2);
查询和结果:
/* query 1 */
select id, name, distance1
from (
select *
from tbl1
where distance1 <= 2.0
order by distance1) a
union
select id, name, distance1
from (
select *
from tbl1
order by distance1
limit 5) b;
/* result 1 */
id;name;distance1
3;Earl of Sandwich ;0.3
4;Nails 'n More ;0.8
22;City Hotel ;1.7
5;Mighty Medicine ;2.1
25;Wonder Wings ;2.5
/* query 2 */
select id, name, distance2
from (
select *
from tbl1
where distance2 <= 2.0
order by distance2) a
union
select id, name, distance2
from (
select *
from tbl1
order by distance2
limit 5) b;
/* result 2 */
id;name;distance2
3;Earl of Sandwich ;0.1
4;Nails 'n More ;0.2
5;Mighty Medicine ;0.5
6;Jean Warehouse ;0.7
9;Ship Safe & Speedy ;0.9
2;Bagel Bonus ;1.2
22;City Hotel ;1.7
此查询的效果与获得的效果一样好 第一个UNION部分选出了<2km。这是必要的,因为你想要所有的比赛 下一部分选择前5名并假设你有一个索引,这是很容易收集的。 两部分的组合(UNION)非常快。
答案 1 :(得分:0)
如果是我,我会让您的查询返回按距离排序的所有位置。然后在PHP中你可以跳到阵列中的第5位(这将是距离第5个最远的地方,因为你已经按距离订购了查询)并检查它是否在2英里内。如果它然后返回前5个,如果没有则返回所有它们。
所以你的查询就是:
SELECT id, name, distance FROM places ORDER BY distance ASC
答案 2 :(得分:0)
SELECT * FROM places ORDER BY distance ASC LIMIT 5
无论如何最近的地方都会被拉(按asc排序), 所以没关系。
LIMIT是从数据库中提取的最大结果, 所以用户获得的最大位置是5, 可能会少但不多。
答案 3 :(得分:0)
你可以肯定使用mysql限制(并鼓励)订单:
SELECT * FROM `table` ORDER BY `distance` ASC LIMIT 5;
“ASC”告诉查询以递增的方式(从最小到最高)对行进行排序。