【问题标题】:How to ORDER BY an unaggregated column in subquery?如何按子查询中的未聚合列排序?
【发布时间】:2021-09-04 16:27:00
【问题描述】:

我正在尝试在 Hasura 中创建一个函数来查询用户附近的帖子。我得到了那个工作,但我也想订购这些帖子。我收到一个 Postgres 错误,上面写着:

"postgres-error : "b.Volume" 列必须出现在 GROUP BY 子句中 或用于聚合函数”

我是 Hasura 和 Postgres 的新手,我不确定您是否可以这样做。 这是我的代码:

CREATE OR REPLACE FUNCTION public.search_posts_near_user(id uuid, distance_kms integer, volume integer)
 RETURNS SETOF user_posts
 LANGUAGE sql
 STABLE
AS $function$
  SELECT  A.id, A.location,
  (SELECT json_agg(row_to_json(B)) FROM "Posts" B
   WHERE (
     ST_Distance(
       ST_Transform(B.location::Geometry, 3857),
       ST_Transform(A.location::Geometry, 3857)
     ) /1000) < distance_kms AND B."Volume" < volume
    ORDER BY B."Volume" Desc
   ) AS nearby_Posts
  FROM users A where A.id = id
$function$

【问题讨论】:

标签: sql postgresql sql-order-by knn hasura


【解决方案1】:

这应该可行:

CREATE OR REPLACE FUNCTION public.search_posts_near_user(
      _id uuid
    , _distance_kms integer
    , _volume integer)
  RETURNS SETOF user_posts
  LANGUAGE sql STABLE AS
$func$
SELECT  A.id, A.location
     , (SELECT json_agg(B.* ORDER BY B."Volume" DESC)
        FROM   "Posts" B
        WHERE  ST_Distance(ST_Transform(B.location::Geometry, 3857)
                         , ST_Transform(A.location::Geometry, 3857))
               < _distance_kms * 1000
        AND    B."Volume" < _volume
      ) AS nearby_Posts
FROM    users A
WHERE   A.id = _id
$func$;

确保函数参数(和变量)不与表列名冲突。我以_ 为前缀。不是绝对必要,而是一个好习惯。

注意我是如何乘以 _distance_kms * 1000 而不是 ST_Distance() / 1000 的方式。出于多种原因,这更好。乘法开始时更便宜,并且可以避免舍入错误。并且操作常量值一次 比每行的计算值便宜得多。最后,您的原始表达式可能会阻止索引支持(如果可用),因为它不是"sargable",这将是修复它的最强有力的理由。

基本上,这是一个 KNN(k 最近邻)类型的问题,可以从正确的查询技术结合正确的索引(通常是 GiST 索引)中受益很多。见:

此外,虽然ORDER BY 附加到聚合表达式很方便,但通常使用ORDER BY 在子查询中排序然后聚合更快。见:

旁白:
我的常规建议是在 Postgres 中仅使用合法的、小写的、未引用的名称。见:

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2023-03-08
    • 1970-01-01
    • 1970-01-01
    • 2016-06-28
    • 2019-04-12
    • 2020-08-14
    • 2011-04-28
    相关资源
    最近更新 更多