【问题标题】:How to select distinct one column but return all columns with acos-cos-radians formula如何选择不同的一列但使用 acos-cos-radians 公式返回所有列
【发布时间】:2020-04-23 12:28:59
【问题描述】:

我想获取一个名为 supplier_products 的表,其中包含以下列

ID Item_id supplier_id variant_id  price    lat        lng   serving_radius(in km)

1     1      2            12       22.00  26.11360000 85.39430000    1
2     1      3            12       44.00  26.11360000 85.39430000    4
3     1      2            13       25.00  26.11360000 85.39430000    4
4     1      3            13       23.00  26.11360000 85.39430000    4

现在用于搜索经纬度附近的供应商产品say($lat = 26.1136;$long = 85.3643;)。我正在使用这个查询

SELECT *, (6371 * acos(cos(radians('$lat')) * cos(radians(lat)) * cos( radians(lng) - radians('$long')) + sin(radians('$lat')) * sin(radians(lat)))) AS distance FROM supplier_products HAVING distance <= serving_radius ORDER BY distance")

上述查询返回为输入$lat &amp; $long 提供服务的所有行。

但现在我只想返回那些具有不同 variant_id 的行的所有列,这些行提供输入 $lat &amp; $long

我尝试使用GROUP BY -

SELECT *, (6371 * acos(cos(radians('$lat')) * cos(radians(lat)) * cos( radians(lng) - radians('$long')) + sin(radians('$lat')) * sin(radians(lat)))) AS distance FROM supplier_products GROUP BY variant_id HAVING distance <= serving_radius")

但它消除了一些所需的行,因为GROUP BYHAVING 子句之前执行。因此,它消除了服务半径内的一些必需行。

我正在使用PHP & MYSQL

编辑-我想要这个作为我的输出

ID Item_id supplier_id variant_id  price    lat        lng   serving_radius(in km)

2     1      3            12       44.00  26.11360000 85.39430000    4
3     1      2            13       25.00  26.11360000 85.39430000    4

ID-1 的行不提供输入 $lat/$long

但我的尝试给出了以下结果 -

ID Item_id supplier_id variant_id  price    lat        lng   serving_radius(in km)

3     1      2            13       25.00  26.11360000 85.39430000    4

因为GROUP BY 消除了2nd row

【问题讨论】:

  • 如果你能提供一个 sql fiddle 会很有帮助
  • 我不明白只有那些具有不同 variant_id 的行的所有列服务...edit您的问题显示您想要的结果示例。
  • 我已经用我的实际数据库值和我需要的输出编辑了这个问题
  • @O.Jones 用你提供的小提琴我得到了想要的输出。感谢您的努力,您能解释一下您使用的查询吗?

标签: php mysql database geospatial


【解决方案1】:

如果您想要可预测的结果,您的要求仍然不完整。你要求从几行中只选择一行。为什么您想要的结果显示 id=3 而不是 id=4?我猜你随机选择了两者之一。

此查询 (https://www.db-fiddle.com/f/USMrhc8gLcRD2rAmuzYzH/0) 会为您执行此操作。

SET @lat := 26.120888;
SET @long := 85.364832;
SELECT ANY_VALUE(supplier_id), variant_id, ANY_VALUE(price)  
FROM  ( SELECT ID,
               (6371 * acos(cos(radians(@lat)) * cos(radians(lat)) *
                cos( radians(lng) - radians(@long)) + sin(radians(@lat)) * 
                sin(radians(lat)))) AS distance
          FROM supplier_products 
     ) t WHERE distance < serving_radius
GROUP BY variant_id

它有一个子查询来显示表格的变体,该变体显示与提供的@lat 和@long 值的距离。它显示 ID 和距离。就是这个。 (https://www.db-fiddle.com/f/guagWYVXXaf7cPkbojj9KD/2)

        SELECT *, 
               (6371 * acos(cos(radians(@lat)) * cos(radians(lat)) *
                cos( radians(lng) - radians(@long)) + sin(radians(@lat)) * 
                sin(radians(lat)))) AS distance
          FROM supplier_products 

然后它在带有 GROUP BY 的外部查询中使用该子查询,见上文。

但是,由于您希望每个变体只有一行,并且您没有告诉我们如果有多行时如何选择该行,查询使用 ANY_VALUE() function 为您的每一列选择一个可用值结果。

8.0 之前的 MySQL 版本不需要 ANY_VALUE() 函数,因为 MySQL 臭名昭著的非标准 GROUP BY 处理:please read this.

当心:如果你让 MySQL 使用这个 ANY_VALUE() 东西,无论是隐式还是显式,你让你的测试人员和你的用户发疯。他们今天有时会得到与上周不同的结果,他们会想知道自己做错了什么。请不要这样做。

还有一件事:您的距离公式因在非常小的距离上抛出异常而臭名昭著。通过像这样修改它以使用 LEAST(),确保它永远不会尝试使用值大于 1 的 ACOS()。 (https://www.db-fiddle.com/f/USMrhc8gLcRD2rAmuzYzH/1)

    (6371 * acos(LEAST(1.0,cos(radians(@lat)) * cos(radians(lat)) *
    cos( radians(lng) - radians(@long)) + sin(radians(@lat)) *
    sin(radians(lat)))))

【讨论】:

  • 对不起,我不明白你答案的最后一部分,即 SMALL DISTANCE 和 ACOS() 部分
  • 试试SELECT ACOS(1.000001); 会抛出异常。您使用的公式有时可以将一个大于 1 的值传递给 ACOS。为什么?舍入误差。 LEAST() 函数可以防止这种情况发生。
猜你喜欢
  • 1970-01-01
  • 2011-09-01
  • 1970-01-01
  • 1970-01-01
  • 2011-09-08
  • 2020-02-02
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多