Ran*_*ize 10 postgresql pivot computed-column
我在这里问了一个问题:https : //stackoverflow.com/questions/43807566/how-to-divide-two-values-from-the-same-column-but-at-different-rows
关于将同一表中同一列但不同行的值进行除法。现在我的问题是我有更多的分子和分母(不同的uns)。仍然是self join用 Postgres 解决这个问题的好方法还是有更好的解决方案?
例子:
| postcode | value | uns |
|----------|-------|-----|
| AA | 40 | 53 |
| BB | 20 | 53 |
| AA | 10 | 54 |
| AA | 20 | 55 |
| AA | 10 | 56 |
| AA | 30 | 57 |
| AA | 50 | 58 |
| BB | 10 | 54 |
| BB | 10 | 55 |
| BB | 70 | 56 |
| BB | 80 | 57 |
| BB | 10 | 58 |
Run Code Online (Sandbox Code Playgroud)
结果应该是:
| postcode | formula |
|----------|------------|
| AA | 18.888... |
| BB | 14.375 |
Run Code Online (Sandbox Code Playgroud)
其中值按邮政编码分组,公式为(带有 uns 的值):
(V53 * V56 + V54 * V57 + V55 * V58) / (V56 + V57 + V58)
Run Code Online (Sandbox Code Playgroud)
注意避免最终被零除。公式可能更复杂,但这是一个很好的例子。
您可以将所有 uns/value 对聚合到一个 JSON 对象中,然后使用它来按名称访问 UNS 值。这需要进行一些转换,因为值只能从 JSON 对象中提取为文本,但该公式看起来与您的描述非常相似:
with vals(postcode, v) as (
select postcode, json_object_agg(uns, value)
from x
group by postcode
), factors (postcode, denominator, divisor) as (
select postcode,
(v->>'53')::decimal * (v->>'56')::decimal + (v->>'54')::decimal * (v->>'57')::decimal + (v->>'55')::decimal * (v->>'58')::decimal,
(v->>'56')::decimal + (v->>'57')::decimal + (v->>'58')::decimal
from vals
)
select postcode,
denominator / nullif(divisor, 0)
from factors;
Run Code Online (Sandbox Code Playgroud)
我将聚合、分母和除数的评估以及最终的除法分为三个步骤,以使其更具可读性。
在线示例:http : //rextester.com/IZYT54566
您可以通过创建函数来简化公式:
create function val(p_vals json, p_uns text)
returns decimal
as $$
select (p_vals ->> p_uns)::decimal;
$$
language sql;
with vals (postcode, v) as (
select postcode, json_object_agg(uns, value)
from x
group by postcode
), factors (postcode, denominator, divisor) as (
select postcode,
val(v, '53') * val(v, '56') + val(v, '54') * val(v, '57') + val(v, '55') * val(v, '58'),
val(v, '56') + val(v, '57') + val(v, '58')
from vals
)
select postcode,
denominator / nullif(divisor, 0)
from factors;
Run Code Online (Sandbox Code Playgroud)
这是一个核心/交叉表问题的核心,就像迈克尔已经准确诊断的那样。
如果您不熟悉tablefuncPostgres 中的模块,请阅读此处的基本说明:
查询变得简单且非常快(比此处介绍的其他解决方案更快):
SELECT (v53 * v56 + v54 * v57 + v55 * v58) / NULLIF(v56 + v57 + v58, 0)
FROM crosstab(
'SELECT postcode, uns, value FROM tbl ORDER BY 1'
, 'SELECT generate_series(53,58)'
) AS ct (postcode text
, v53 numeric, v54 numeric, v55 numeric
, v56 numeric, v57 numeric, v58 numeric);
Run Code Online (Sandbox Code Playgroud)
NULLIF以防止被零除。
dbfiddle在这里
| 归档时间: |
|
| 查看次数: |
2121 次 |
| 最近记录: |