为什么没有"?;产品();SQL中的聚合函数?

为什么没有"?;产品();SQL中的聚合函数?,sql,oracle,aggregate-functions,Sql,Oracle,Aggregate Functions,当有Sum()、min()、max()、avg()、count()函数时,有人可以帮助理解为什么没有product()内置函数。这个聚合函数最有效的用户实现是什么 谢谢, Trinity您可以使用光标模拟product()。如果您让我们知道您使用的是哪个数据库平台,那么我们可能会给您一些示例代码。您可以在SQL 2005及更高版本中使用。在Postgresql中,您可以在Postgres中执行此操作,同样可以使用,因为乘积只表示总和的倍数,所以在SQL中,它们没有引入乘积聚合函数 例如:6*4可

当有Sum()、min()、max()、avg()、count()函数时,有人可以帮助理解为什么没有product()内置函数。这个聚合函数最有效的用户实现是什么

谢谢,
Trinity

您可以使用光标模拟product()。如果您让我们知道您使用的是哪个数据库平台,那么我们可能会给您一些示例代码。

您可以在SQL 2005及更高版本中使用。在Postgresql中,您可以在Postgres中执行此操作,同样可以使用

,因为乘积只表示总和的倍数,所以在SQL中,它们没有引入乘积聚合函数

例如:6*4可以通过

或者像6+6+6+6那样给自己加上6,4次

加4,6倍于4+4+4+4+4+4


因此,如果有可用的指数函数和对数函数,则给出相同的结果,然后:

PRODUCT(TheColumn) = EXP(SUM(LN(TheColumn)))

我将重点讨论为什么它不是一个标准函数

  • 聚合函数是基本的统计函数,乘积不是
  • 应用于普通数值数据,结果在大多数情况下会超出范围(溢出),因此它没有什么通用性

    • 它可能被遗漏了,因为大多数人不需要它,而且它可以在大多数数据库中轻松定义

      PostgreSQL的解决方案:

      CREATE OR REPLACE FUNCTION product_sfunc(state numeric, factor numeric)
      RETURNS numeric AS $$
          SELECT $1 * $2
      $$ LANGUAGE sql;
      
      CREATE AGGREGATE product (
          sfunc = product_sfunc,
          basetype = numeric,
          stype = numeric,
          initcond = '1'
      );
      

      我可以证实,使用
      product()
      聚合函数确实很少见,但我有一个非常有效的例子,特别是处理必须在报告中呈现给用户的高度聚合数据

      它使用exp(sum(ln(multipleTheseColumnValues))“技巧”
      ,如另一篇文章和其他互联网来源所述

      报告(应关注显示,并包含尽可能少的数据计算逻辑,以提供更好的可维护性和灵活性)基本上显示了这些数据以及一些图形:

       DESCR                              SUM       
       ---------------------------------- ----------
       money available in 2013            33233235.3
       money spent in 2013                 4253235.3
       money bound to contracts in 2013     34333500
       money spent 2013 in % of available         12
       money bound 2013 in % of available        103
      
      (在现实生活中,它有点复杂,用于国家预算方案。)

      它聚集了前3行中发现的相当复杂的数据。 我不想通过计算以下行(第4行和第5行)的百分比值:

      • 在相当愚蠢的(应该是这样的)报告中使用一些奇特的逻辑(使用
        JasperReports
        BIRT报告
        或类似的方法)执行此操作(只需要取任意数量的这样的行,带有描述符
        descr
        和数字
        sum
      • 我也不想多次计算基础数据(
        money available
        money spend
        money bound
        ),只为了计算百分比值
      因此,我使用了另一个技巧,涉及产品()功能的使用。 (考虑到上述限制,如果有人知道实现这一点的更好方法,我很乐意知道:-)

      整个简化示例作为下面的一个可执行SQL提供。 也许它可以帮助一些Oracle人员确信,这种功能并不像乍一看那样罕见或不值得提供。

      with 
          -- we have some 10g database without pivot/unpivot functionality
      
          -- what is interesting for various summary reports
          sum_data_meta as (  
              select            'MA' as sum_id, 'money available in 2013' as descr,   1 as agg_lvl  from dual
              union all select  'MS',           'money spent in 2013',                1             from dual
              union all select  'MB',           'money bound to contracts in 2013',   1             from dual
              union all select  'MSP',          'money spent 2013 in % of available', 2             from dual
              union all select  'MBP',          'money bound 2013 in % of available', 2             from dual
          )
          /* select * from sum_data_meta
           SUM_ID DESCR                              AGG_LVL
           ------ ---------------------------------- -------
           MA     money available in 2013                  1
           MS     money spent in 2013                      1
           MB     money bound to contracts in 2013         1
           MSP    money spent 2013 in % of available       2
           MBP    money bound 2013 in % of available       2
          */
      
          -- 1st level of aggregation with the base data (the data actually comes from complex (sub)SQLs)
          ,sum_data_lvl1_base as (
              select            'MA' as sum_id,  33233235.3 as sum  from dual
              union all select  'MS',            4253235.3          from dual
              union all select  'MB',            34333500           from dual
          )
          /* select * from sum_data_lvl1_base
           SUM_ID SUM
           ------ ----------
           MA     33233235.3
           MS      4253235.3
           MB     34333500.0
       */
      
          -- 1st level of aggregation with enhanced meta data infos
          ,sum_data_lvl1 as (
              select
                  m.descr,
                  b.sum,
                  m.agg_lvl,
                  m.sum_id
              from sum_data_meta m
                  left outer join sum_data_lvl1_base b on (b.sum_id=m.sum_id)
          )
          /* select * from sum_data_lvl1
           DESCR                              SUM        AGG_LVL SUM_ID
           ---------------------------------- ---------- ------- ------
           money available in 2013            33233235.3       1 MA
           money spent in 2013                 4253235.3       1 MS
           money bound to contracts in 2013   34333500.0       1 MB
           money spent 2013 in % of available          -       2 MSP
           money bound 2013 in % of available          -       2 MBP
          */
      
      select
          descr,
      
          case  
              when agg_lvl < 2 then  sum
              when agg_lvl = 2 then  -- our level where we have to calculate some things based on the previous level calculations < 2
                  case 
                      when sum_id = 'MSP' then  
                          -- we want to calculate MS/MA by tricky aggregating the product of 
                          -- (MA row:) 1/33233235.3 * (MS:) 4253235.3/1 * (MB:) 1/1 * (MSP:) 1/1 * (MBP:) * 1/1
                          trunc(  -- cut of fractions, e.g. 12.7981 => 12
                              exp(sum(ln(  -- trick simulating product(...) as mentioned here: http://stackoverflow.com/a/404761/1915920
                                      case when sum_id = 'MS' then sum else 1 end
                                  / case when sum_id = 'MA' then sum else 1 end
                              )) over ())  -- "over()" => look at all resulting rows like an aggregate function  
                              * 100  -- % display style
                        )
                      when sum_id = 'MBP' then
                          -- we want to calculate MB/MA by tricky aggregating the product as shown above with MSP 
                          trunc(
                              exp(sum(ln(
                                      case when sum_id = 'MB' then sum else 1 end
                                  / case when sum_id = 'MA' then sum else 1 end
                              )) over ())  
                              * 100
                        )
                      else -1  -- indicates problem
                  end
              else null  -- will be calculated in a further step later on
          end as sum,
      
          agg_lvl,
          sum_id
      from sum_data_lvl1
      /*
       DESCR                              SUM        AGG_LVL SUM_ID
       ---------------------------------- ---------- ------- ------
       money available in 2013            33233235.3       1 MA
       money spent in 2013                 4253235.3       1 MS
       money bound to contracts in 2013     34333500       1 MB
       money spent 2013 in % of available         12       2 MSP
       money bound 2013 in % of available        103       2 MBP
      */
      
      与
      --我们有些10g数据库没有pivot/unpivot功能
      --各种摘要报告的有趣之处是什么
      总和数据元为(
      选择“MA”作为金额id,“2013年可用资金”作为描述,1作为双重账户中的累计金额
      工会全部选择“MS”,“2013年花费的钱”,1来自dual
      union all从dual中选择“MB”,“2013年合同绑定资金”,1
      union all选择“MSP”,“2013年花费的金额占可用金额的百分比”,2来自dual
      union all选择“MBP”,“2013年可用资金的百分比”,2个来自dual
      )
      /*从总和数据元中选择*
      总ID描述汇总表
      ------ ---------------------------------- -------
      2013年可用的MA资金1
      MS 2013年的支出1
      2013年合同金额为MB 1
      MSP在2013年花费的资金占可用资金的2%
      2013年MBP资金约束,占可用资产的2%
      */
      --基本数据的第一级聚合(数据实际上来自复杂(子)SQL)
      ,总和为1级数据,基数为(
      选择'MA'作为sum_id,从dual中选择33233235.3作为sum
      union all从双通道选择“MS”,4253235.3
      union all选择“MB”,从dual中选择34333500
      )
      /*从总和数据层1底部选择*
      SUM\u ID SUM
      ------ ----------
      MA 33233235.3
      MS 4253235.3
      MB 34333500.0
      */
      --具有增强元数据信息的第一级聚合
      ,将第1级数据求和为(
      选择
      m、 描述,
      b、 总之,
      m、 阿格卢尔,
      m、 总数
      从sum_data_meta m
      左外连接和数据第1层基于b(b.sum\U id=m.sum\U id)
      )
      /*从sum_data_lvl1中选择*
      描述汇总汇总汇总ID
      ---------------------------------- ---------- ------- ------
      2013年可用资金33233235.3 1 MA
      2013年花费的资金4253235.3 1毫秒
      2013年合同金额34333500.01百万
      2013年花费的资金占可用资金的百分比-2 MSP
      2013年现金受限,占可用资金的百分比-2MBP
      */
      选择
      描述,
      案例
      当agg_lvl<2时,则求和
      当agg_lvl=2时,那么——我们的水平,我们必须根据前面的水平计算<2来计算一些东西
      案例
      当sum_id='MSP'时,则
      --我们想通过计算MS/MA