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