postgresql 中函数中的 "order by" 在调用时略有不同
The "order by" in a function in postgresql is reversed when called slightly different
我有一个 select 来自存储交易的 table 的功能。该功能更长,所以我制作了一个简洁的版本来尝试说明我遇到的问题。原始函数有一个“联合所有”来获得总和,除法求和,最后是我遗漏的乘积。输出将转换为 PDF 文件。我看到的行为似乎不是函数本身引起的,而是当我以两种方式调用函数时引起的。
我使用组织 ID 加入客户 table。一些客户使用相同的组织 ID 但不同的客户 ID 注册了不止一次。有一些我无法控制的原因导致客户可以多次注册。因此,为了不重复行,我对这些情况进行了豁免-table。
然后我使用案例“排序”,因为我需要按特定顺序显示产品。第一次调用时,产品按需要排序,但后者排序相反。
这是在 ubuntu 18.04 LTS 和 postgresql 10.12 上。
create or replace function f(quarter integer, year integer, cid text)
returns table (cid text, name text, product text, quantity numeric, vat text, amount numeric)
as
$body$
select
cid,
name,
internal_product,
sum(quantity) as quantity,
vat,
sum(amount) as amount
from transaction
where
extract('quarter' from created_at) = and extract('year' from created_at) =
group by
cid,
name,
internal_product,
vat) as VAT
where cid in ()
order by
name desc,
case internal_product
when 'product A' then 1
when 'extra B' then 2
when 'large C' then 3
when 'small D' then 4
when '' then 99
end
$body$
language sql;
这是我想要的排序方式。
select
c.cid, c.cidtext, f.*
from
f(2,2020,'958935420') f
join
customer c
on
f.cid = c.cid;
添加豁免项 table 会反转排序。
select
c.cid, c.cidtext, f.*
from
f(2,2020,'958935420') f
join
customer c
on
f.cid = c.cid
where c.cid not in (select cid from exempt_cid);
一个 SELECT
语句只有在它有一个 ORDER BY
子句时才有明确的顺序。由于调用该函数的语句没有 ORDER BY
,您没有那个保证。
实际上,这取决于执行计划(使用EXPLAIN
)。该函数本身将 return 值按所需顺序排列,如果执行计划的其余部分没有任何内容会扰乱该顺序,您就可以了。
我的建议是 永远不要 将 ORDER BY
子句添加到视图定义或函数结果中,但始终将它放在它所属的位置,在调用查询中。 PostgreSQL 不会优化此类 ORDER BY
子句,您最终可能会付出某种代价而没有任何好处。
如果您在函数中排序以简化代码维护,以防将来必须更改排序并且您不想更新多个调用查询:
create or replace function f(quarter integer, year integer, cid text)
returns table (cid text, name text, product text, quantity numeric, vat text, amount numeric)
as
$body$
select
cid,
name,
internal_product,
sum(quantity) as quantity,
vat,
sum(amount) as amount,
row_number()
over (order by name desc,
case internal_product
when 'product A' then 1
when 'extra B' then 2
when 'large C' then 3
when 'small D' then 4
when '' then 99
end) as sort_key
from transaction
where
extract('quarter' from created_at) = and extract('year' from created_at) =
group by
cid,
name,
internal_product,
vat) as VAT
where cid in ()
$body$
language sql;
那么您的通话将如下所示:
select
c.cid, c.cidtext, f.cid, f.name, f.internal_product, f.quantity, f.vat, f.amount
from
f(2,2020,'958935420') f
join
customer c
on
f.cid = c.cid
order by sort_key;
我有一个 select 来自存储交易的 table 的功能。该功能更长,所以我制作了一个简洁的版本来尝试说明我遇到的问题。原始函数有一个“联合所有”来获得总和,除法求和,最后是我遗漏的乘积。输出将转换为 PDF 文件。我看到的行为似乎不是函数本身引起的,而是当我以两种方式调用函数时引起的。
我使用组织 ID 加入客户 table。一些客户使用相同的组织 ID 但不同的客户 ID 注册了不止一次。有一些我无法控制的原因导致客户可以多次注册。因此,为了不重复行,我对这些情况进行了豁免-table。
然后我使用案例“排序”,因为我需要按特定顺序显示产品。第一次调用时,产品按需要排序,但后者排序相反。
这是在 ubuntu 18.04 LTS 和 postgresql 10.12 上。
create or replace function f(quarter integer, year integer, cid text)
returns table (cid text, name text, product text, quantity numeric, vat text, amount numeric)
as
$body$
select
cid,
name,
internal_product,
sum(quantity) as quantity,
vat,
sum(amount) as amount
from transaction
where
extract('quarter' from created_at) = and extract('year' from created_at) =
group by
cid,
name,
internal_product,
vat) as VAT
where cid in ()
order by
name desc,
case internal_product
when 'product A' then 1
when 'extra B' then 2
when 'large C' then 3
when 'small D' then 4
when '' then 99
end
$body$
language sql;
这是我想要的排序方式。
select
c.cid, c.cidtext, f.*
from
f(2,2020,'958935420') f
join
customer c
on
f.cid = c.cid;
添加豁免项 table 会反转排序。
select
c.cid, c.cidtext, f.*
from
f(2,2020,'958935420') f
join
customer c
on
f.cid = c.cid
where c.cid not in (select cid from exempt_cid);
一个 SELECT
语句只有在它有一个 ORDER BY
子句时才有明确的顺序。由于调用该函数的语句没有 ORDER BY
,您没有那个保证。
实际上,这取决于执行计划(使用EXPLAIN
)。该函数本身将 return 值按所需顺序排列,如果执行计划的其余部分没有任何内容会扰乱该顺序,您就可以了。
我的建议是 永远不要 将 ORDER BY
子句添加到视图定义或函数结果中,但始终将它放在它所属的位置,在调用查询中。 PostgreSQL 不会优化此类 ORDER BY
子句,您最终可能会付出某种代价而没有任何好处。
如果您在函数中排序以简化代码维护,以防将来必须更改排序并且您不想更新多个调用查询:
create or replace function f(quarter integer, year integer, cid text)
returns table (cid text, name text, product text, quantity numeric, vat text, amount numeric)
as
$body$
select
cid,
name,
internal_product,
sum(quantity) as quantity,
vat,
sum(amount) as amount,
row_number()
over (order by name desc,
case internal_product
when 'product A' then 1
when 'extra B' then 2
when 'large C' then 3
when 'small D' then 4
when '' then 99
end) as sort_key
from transaction
where
extract('quarter' from created_at) = and extract('year' from created_at) =
group by
cid,
name,
internal_product,
vat) as VAT
where cid in ()
$body$
language sql;
那么您的通话将如下所示:
select
c.cid, c.cidtext, f.cid, f.name, f.internal_product, f.quantity, f.vat, f.amount
from
f(2,2020,'958935420') f
join
customer c
on
f.cid = c.cid
order by sort_key;