Alternative to Self Join
You can aggregate all uns/value pairs into a JSON object, then use that to access the UNS values by name. This requires some casting as the values can only be extracted as text from the JSON object, but the formula looks very similar to your description then:

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-&gt;&gt;'53')::decimal * (v-&gt;&gt;'56')::decimal + (v-&gt;&gt;'54')::decimal * (v-&gt;&gt;'57')::decimal + (v-&gt;&gt;'55')::decimal * (v-&gt;&gt;'58')::decimal,
         (v-&gt;&gt;'56')::decimal + (v-&gt;&gt;'57')::decimal + (v-&gt;&gt;'58')::decimal
  from vals
)
select postcode, 
       denominator / nullif(divisor, 0)
from factors;


I have divided the aggregation, the evaluation of the denominator and divisor and the final division into three steps to make it more readable. 

Online example: http://rextester.com/IZYT54566



You can simplify the formula by creating a function:

create function val(p_vals json, p_uns text)
  returns decimal
as $$
  select (p_vals -&gt;&gt; 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;