选择哪个WHERE子句与结果匹配

时间:2019-08-21 07:28:55

标签: sql postgresql

我有一个数据库,我想在其中进行快速而粗糙的geohash匹配。我想通过降低geohash的分辨率来找到第一个,最相似的匹配项,直到获得成功为止。以下查询为我提供了所有我感兴趣的geohash,但是我需要从以下集合中选择与我的原始geohash最接近的匹配。

SELECT business_address, geohash FROM geolocation
    WHERE
        geohash LIKE (CONCAT(SUBSTRING(:'geohash', 1, 12), '%')) OR
        geohash LIKE (CONCAT(SUBSTRING(:'geohash', 1, 11), '%')) OR
        geohash LIKE (CONCAT(SUBSTRING(:'geohash', 1, 10), '%')) OR
        geohash LIKE (CONCAT(SUBSTRING(:'geohash', 1, 9), '%')) OR
        geohash LIKE (CONCAT(SUBSTRING(:'geohash', 1, 8), '%')) OR
        geohash LIKE (CONCAT(SUBSTRING(:'geohash', 1, 7), '%'));

问题是我没有明确的方法来订购此结果,也没有添加可用于订购结果的列。仅将结果限制为1并按geohash排序是不够的,因为较低分辨率的匹配项可能位于全分辨率geohash的两侧。有没有一种方法可以让我无需执行6个单独的查询?

3 个答案:

答案 0 :(得分:2)

您可以通过为所有匹配项提供匹配的slno,然后找到最小的slno以获得最接近的匹配项来做到这一点

WITH CTE AS (
SELECT business_address, geohash, 12 AS SLNO FROM geolocation WHERE geohash LIKE (CONCAT(SUBSTRING(:'geohash', 1, 12), '%')) 
UNION ALL 
SELECT business_address, geohash, 11 FROM geolocation WHERE geohash LIKE (CONCAT(SUBSTRING(:'geohash', 1, 11), '%')) 
UNION ALL 
SELECT business_address, geohash, 10 FROM geolocation WHERE geohash LIKE (CONCAT(SUBSTRING(:'geohash', 1, 10), '%')) 
UNION ALL 
SELECT business_address, geohash, 9 FROM geolocation WHERE geohash LIKE (CONCAT(SUBSTRING(:'geohash', 1, 9), '%')) 
UNION ALL 
SELECT business_address, geohash, 8 FROM geolocation WHERE geohash LIKE (CONCAT(SUBSTRING(:'geohash', 1, 8), '%')) 
UNION ALL 
SELECT business_address, geohash, 7 FROM geolocation WHERE geohash LIKE (CONCAT(SUBSTRING(:'geohash', 1, 7), '%'));
)
SELECT business_address, geohash, MIN(SLNO) AS SLNO FROM CTE   --- change MIN(Slno) as per your need
GROUP BY business_address, geohash

或者您可以根据需要进行更改。

答案 1 :(得分:0)

这可能与您要查找的不完全相同,但是您可以使用联合来执行此操作。在每个查询中添加一个固定列,设置返回结果集的优先级,并以此优先级从联合中订购最终结果集。

它看起来像六个查询(也许也可以这样),但是我认为没有其他方法。我不擅长查询优化,但是最终结果有可能实际上像在后台执行单个查询一样。

答案 2 :(得分:0)

您可以使用generate_series()

SELECT DISTINCT ON (gl.business_address) gl.business_address, gl.geohash
FROM geolocation gl JOIN
     generate_series(12, 7, -1) gs(val)
     ON gl.geohash LIKE SUBSTRING(:'geohash', 1, gs.val) || '%')
ORDER BY gl.business_address, gl.geohash ASC;

之所以使用DISTINCT ON,是因为它通常比GROUP BY快,并且允许您包含其他列。

如果要比较的值不是真正的连续数字,请使用VALUES()

SELECT DISTINCT ON (gl.business_address) gl.business_address, gl.geohash
FROM geolocation gl JOIN
     (VALUES (12), (11), (10), (9), (8), (7)) v(val)
     ON gl.geohash LIKE SUBSTRING(:'geohash', 1, v.val) || '%')
ORDER BY gl.business_address, gl.geohash ASC;