【问题标题】:Count number of points within certain distance ranges from another set of points计算距另一组点一定距离范围内的点数
【发布时间】:2015-05-11 23:08:51
【问题描述】:

我有以下数据,它给出了距离任何商店位置 10,000 米范围内的客户数量:

SELECT COUNT(*) as customer_count FROM customer_table c
WHERE EXISTS(
SELECT 1 FROM locations_table s
WHERE ST_Distance_Sphere(s.the_geom, c.the_geom) < 10000
)

我需要的是这个查询不仅返回10,000米内的客户数量,而且还返回以下内容。内的客户数量...

  1. 10000米
  2. 超过 10,000,但小于 50,000
  3. 超过 50,000,但小于 10,0000
  4. 超过100,000

...任何地点。

我对这种工作方式持开放态度。对于给定的客户,只计算一次(到任何商店的最短距离),这将每个人都计算一次。我意识到这可能非常复杂。我也愿意让人们被多次计算,无论如何这确实是准确的值,并且认为应该更简单。

感谢您的任何指导。

【问题讨论】:

    标签: postgresql postgis


    【解决方案1】:

    您可以相对轻松地执行这两种类型的查询。但是这里的一个问题是您不知道哪些客户与哪些商店位置相关联,这似乎是一件有趣的事情。如果需要,请在查询中使用 locations_table 的 PK 和 store_name。请参阅下面的位置 id 和 store_name 的两个选项。强调两个选项之间的区别:

    • 第一个选项表示每个商店位置的所有客户,每个商店位置的每个距离等级中有多少客户。
    • 第二个选项表示每个商店位置的每个距离等级中有多少客户,仅针对每个客户最近的商店位置

    这是对O(n x m) 运行顺序的查询(通过customer_tablelocations_table 之间的CROSS JOIN 实现)并且随着任一表中行数的增加可能会变得相当慢。

    统计所有距离等级的客户

    您应该在客户与商店位置的距离之间创建一个CROSS JOIN,然后按照您定义的商店位置 ID、名称和最大距离类别对它们进行分组。您可以使用VALUES 命令从您的距离类中创建一个“表”,然后您可以在任何查询中简单地使用它:

    SELECT loc_dist.id, loc_dist.store_name, grps.grp, count(*)
    FROM (
        SELECT s.id, s.store_name, ST_Distance_Sphere(s.the_geom, c.the_geom) AS dist
        FROM customer_table c, locations_table s) AS loc_dist
    JOIN (
        VALUES(1, 10000.), (2, 50000.), (3, 100000.), (4, 1000000.)
      ) AS grps(grp, dist) ON loc_dist.dist < grps.dist
    GROUP BY 1, 2, 3
    ORDER BY 1, 2, 3;
    

    统计最近距离等级的客户

    如果您只想将客户列在最近的距离类别中,那么您应该在 customer_tablelocations_table 上设置与前一种情况相同的 CROSS JOIN,然后只需选择最低的组(即最近的商店) 在查询中使用CASE 子句和GROUP BY 像以前一样存储位置ID、名称和距离类:

    SELECT 
      id, store_name,
      CASE
        WHEN dist <  10000. THEN 1
        WHEN dist <  50000. THEN 2
        WHEN dist < 100000. THEN 3
        ELSE 4
      END AS grp,
      count(*)
    FROM (
        SELECT s.id, s.store_name, ST_Distance_Sphere(s.the_geom, c.the_geom) AS dist
        FROM customer_table c, locations_table s) AS loc_dist
    GROUP BY 1, 2, 3
    ORDER BY 1, 2, 3;
    

    【讨论】:

    • 这很有帮助!感谢您的详细回答。你给我的第一段代码效果很好,超出了我的预期。一个问题。如何将locations_table 中的另一列添加到最终结果中?这将是一个列store_name。那可能吗?第二段代码对我不起作用。它给了我一个错误:“缺少表“cust_dist”的 FROM 子句条目”
    • 还有一个问题...对于代码的第一位,我没有为每个位置输出所有距离grp,而是尝试通过删除loc_dist.id 为每个距离组获取一行来自SELECT。这有效,但给了我没有意义的数字。对于grp 4,该值大于我的客户数据库中的人数。我希望最大值是人数。
    • 回复。错误:我在CASE 子句中使用cust_dist,但应该是loc_dist;查看更新的答案。 (最初我与 cust_dist 合作,但从您的另一个问题中,我意识到您对客户相对于商店位置的居住地感兴趣,因此我更改了表名。)
    • 从第一个查询中取出 loc_dist.id 意义不大,至少对于距离等级 4 而言。它将为您提供每个距离等级中有多少客户的总和,对于所有人商店合并。请记住,所有客户都在所有商店的距离等级 4 中,因此您的总人数应该是客户数量的 4 倍。
    • 回复。 store_name:您可以简单地在子查询中添加它,然后在主查询中添加GROUP BY;查看更新的答案。
    猜你喜欢
    • 2011-02-07
    • 1970-01-01
    • 1970-01-01
    • 2023-04-03
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多