如何 ORDER BY 子查询中的未聚合列?
How to ORDER BY an unaggregated column in subquery?
我正在尝试在 Hasura 中创建一个函数来查询用户附近的帖子。我得到了那个工作,但我也想订购这些帖子。我收到一个 Postgres 错误:
"postgres-error : column "b.Volume" must appear in the GROUP BY clause
or be used in an aggregate function"
我是 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$
这应该有效:
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$;
确保函数参数(和变量)不与 table 列名称冲突。我以 _
作为前缀。不是绝对必要,而是一个好习惯。
请注意我是如何乘以 _distance_kms * 1000
而不是像您那样乘以 ST_Distance() / 1000
的。出于多种原因,这更好。乘法一开始成本较低,并且可以避免舍入错误。与每行的计算值相比,操纵常量值 一次 要便宜得多。最后,您的原始表达式可能会阻止索引支持(如果可用),因为它是非 "sargable",这将是修复它的最有力理由。
基本上,这是一个 KNN(k 最近邻)类型的问题,可以从正确的查询技术结合正确的索引(通常是 GiST)中受益 很多指数。参见:
此外,虽然附加到聚合表达式的 ORDER BY
工作起来很方便,但在子查询中使用 ORDER BY
排序然后聚合通常更快。参见:
旁白:
我的一贯建议是在 Postgres 中只使用合法的、小写的、不带引号的名称。参见:
- Are PostgreSQL column names case-sensitive?
我正在尝试在 Hasura 中创建一个函数来查询用户附近的帖子。我得到了那个工作,但我也想订购这些帖子。我收到一个 Postgres 错误:
"postgres-error : column "b.Volume" must appear in the GROUP BY clause or be used in an aggregate function"
我是 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$
这应该有效:
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$;
确保函数参数(和变量)不与 table 列名称冲突。我以 _
作为前缀。不是绝对必要,而是一个好习惯。
请注意我是如何乘以 _distance_kms * 1000
而不是像您那样乘以 ST_Distance() / 1000
的。出于多种原因,这更好。乘法一开始成本较低,并且可以避免舍入错误。与每行的计算值相比,操纵常量值 一次 要便宜得多。最后,您的原始表达式可能会阻止索引支持(如果可用),因为它是非 "sargable",这将是修复它的最有力理由。
基本上,这是一个 KNN(k 最近邻)类型的问题,可以从正确的查询技术结合正确的索引(通常是 GiST)中受益 很多指数。参见:
此外,虽然附加到聚合表达式的 ORDER BY
工作起来很方便,但在子查询中使用 ORDER BY
排序然后聚合通常更快。参见:
旁白:
我的一贯建议是在 Postgres 中只使用合法的、小写的、不带引号的名称。参见:
- Are PostgreSQL column names case-sensitive?