【问题标题】:how to build a function in Postgres that calculats Percentage from two "select count(*)" queries?如何在 Postgres 中构建一个从两个“select count(*)”查询中计算百分比的函数?
【发布时间】:2016-03-31 09:02:12
【问题描述】:

我正在尝试构建一个函数来返回一定比例的具有特定条件的行。

这是我的尝试:

CREATE OR REPLACE FUNCTION osm_prozent ()
RETURNS integer AS $$
DECLARE 
      a integer;
      b integer;
      ergebnis integer;
BEGIN
  a = select into a count(*)
    from osm_street;
  b = select into b count(*)
    from osm_street
    where hausnummer like '%-%'
    or hausnummer like '% %' 
    or hausnummer like '%/%' 
    or hausnummer like '%;%'
    or hausnummer like '%,%'
    or hausnummer ~ '([a-z,A-Z])';  

  ergebnis = (b/a)*100;
  return ergebnis;
END;
$$ LANGUAGE plpgsql;

变量a207000,变量b11000. 最后我应该有类似5.31% 的东西。

有人可以帮忙正确编写这个函数吗?

【问题讨论】:

  • 如果你使用 (b/a) * 100 你将得到 5.31。在您的计算中,b 高于 a,您将获得 6 %

标签: sql postgresql plpgsql


【解决方案1】:

您可以按重要性顺序进行两项明显的改进:

  1. 让 1 次通过桌子而不是 2 次通过
  2. 简化第二个查询的 where 条件

先处理第二项:

可以将 where 条件更改为仅使用 one 正则表达式测试进行一次比较。这个表达式:

where hausnummer like '%-%'
or hausnummer like '% %' 
or hausnummer like '%/%'
or hausnummer like '%;%'
or hausnummer like '%,%'
or hausnummer ~ '([a-z,A-Z])'

可以简写为:

where hausnummer ~ '[a-z,A-Z /;-]'

接下来,要只通过表一次,请在捕获count(*) 的同时捕获命中数的条件上使用sum()。以上述改进为条件,您的查询可以变成:

select 100.0 * sum(case when hausnummer ~ '[a-z,A-Z /;-]' then 1 end) / count(*)
from osm_street

除非您需要一个存储过程,否则您现在可以完全省去它,因为您可以通过一个简单的查询获得结果。

如果您迫切需要一个存储过程(不推荐),它只是上述查询的一个薄包装器(不添加任何值):

CREATE OR REPLACE FUNCTION osm_prozent () RETURNS double precision AS $$
BEGIN
  RETURN select 100.0 * sum(case when hausnummer ~ '[a-z,A-Z /;-]' then 1 end) / count(*) from osm_street;
END;
$$ LANGUAGE plpgsql;

请注意,我怀疑您的最后一个条件 hausnummer ~ '([a-z,A-Z])' 不是您想要的。首先,括号是多余的,可以在不改变含义的情况下删除,即与hausnummer ~ '[a-z,A-Z]'相同,如果hausnummber包含字母或逗号,则为true。

如果这不是您想要的,请对此答案发表评论,说明您真正想要什么。

【讨论】:

  • OP 真正想要的绝不应该只是发表评论。它应该在问题中。我假设“存储过程”是指存储过程? Postgres 没有存储过程,只有几乎相同但不完全相同的函数。
  • @erwin 我非常尊重您的数据库知识,但我认为您说 PG“没有存储过程”是在扯皮; docPL/pgSQL ... 可用于创建函数和触发过程,并且它们是存储的,因此它们是存储过程。此外,“存储过程”是业界对此类事物的通用术语。此外,恕我直言,在 Postgres 上下文中调用这些存储过程不会产生误导或导致混淆。
  • 重要的区别是 Postgres 函数(相对于真正的存储过程)总是在单个事务中运行,因此不能开始或提交事务,也不能运行像 VACUUMCREATE INDEX CONCURRENTLY 这样的命令(其中不能在事务块内运行)。更多:stackoverflow.com/a/28251922/939860
【解决方案2】:

您的正则表达式过滤器混合了几个喜欢可以简化为单个正则表达式(另请注意,您的正则表达式通过添加括号增加了不必要的负载,并且 a-z 和 A-Z 之间的逗号不是分隔符,而是匹配逗号为好吧,您还将 TWICE! 包含在您的类似比较列表中)。一个更简单的函数代码是:

CREATE OR REPLACE FUNCTION osm_prozent () RETURNS double precision AS $$
  SELECT 100. * (SELECT COUNT(*) FROM osm_street WHERE hausnummer ~* '[a-z /;,-]') / (SELECT COUNT(*) FROM osm_street);
$$ LANGUAGE sql;

【讨论】:

  • 嗨,我收到此错误:错误:运算符不存在:文本 ~ 未知第 2 行:...(SELECT COUNT() FROM osm_street WHERE hausnummer *~ '[a-z /... ^ 提示:没有运算符与给定的名称和参数类型匹配。您可能需要添加显式类型转换。
  • 对不起,错字(我输入了*~ 而不是~*)。我现在在代码中更正了它。 ~ 使用区分大小写的正则表达式匹配,而~* 使用不区分大小写的正则表达式匹配:)
猜你喜欢
  • 2013-03-16
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2015-04-05
  • 1970-01-01
  • 2014-04-28
  • 1970-01-01
  • 2015-05-12
相关资源
最近更新 更多