Dav*_*vis 10 postgresql plpgsql postgresql-9.1 number-formatting
希望为一系列物质计算最合适的计量单位,其中物质以不同(但兼容)的单位体积给出。
单位转换表存储各种单位以及这些单位之间的关系:
id unit coefficient parent_id
36 "microlitre" 0.0000000010000000000000000 37
37 "millilitre" 0.0000010000000000000000000 5
5 "centilitre" 0.0000100000000000000000000 18
18 "decilitre" 0.0001000000000000000000000 34
34 "litre" 0.0010000000000000000000000 19
19 "dekalitre" 0.0100000000000000000000000 29
29 "hectolitre" 0.1000000000000000000000000 33
33 "kilolitre" 1.0000000000000000000000000 35
35 "megalitre" 1000.0000000000000000000000 0
Run Code Online (Sandbox Code Playgroud)
按系数排序表明将parent_id
子单元与其上级数值联系起来。
可以使用以下命令在 PostgreSQL 中创建此表:
CREATE TABLE unit_conversion (
id serial NOT NULL, -- Primary key.
unit text NOT NULL, -- Unit of measurement name.
coefficient numeric(30,25) NOT NULL DEFAULT 0, -- Conversion value.
parent_id integer NOT NULL DEFAULT 0, -- Relates units in order of increasing measurement volume.
CONSTRAINT pk_unit_conversion PRIMARY KEY (id)
)
Run Code Online (Sandbox Code Playgroud)
应该有一个外键 from parent_id
to id
。
物质表列出了特定数量的物质。例如:
id unit label quantity
1 "microlitre" mercury 5
2 "millilitre" water 500
3 "centilitre" water 2
4 "microlitre" mercury 10
5 "millilitre" water 600
Run Code Online (Sandbox Code Playgroud)
该表可能类似于:
CREATE TABLE substance (
id bigserial NOT NULL, -- Uniquely identifies this row.
unit text NOT NULL, -- Foreign key to unit conversion.
label text NOT NULL, -- Name of the substance.
quantity numeric( 10, 4 ) NOT NULL, -- Amount of the substance.
CONSTRAINT pk_substance PRIMARY KEY (id)
)
Run Code Online (Sandbox Code Playgroud)
您将如何创建一个查询,该查询使用具有整数(和可选的实分量)的最少数字来查找表示物质总和的测量值?
例如,您将如何返回:
quantity unit label
15 microlitre mercury
112 centilitre water
Run Code Online (Sandbox Code Playgroud)
但不是:
quantity unit label
15 microlitre mercury
1.12 litre water
Run Code Online (Sandbox Code Playgroud)
因为 112 的实数比 1.12 少,而 112 比 1120 小。但在某些情况下,使用实数更短——例如 1.1 升 vs 110 厘升。
大多数情况下,我无法根据递归关系选择正确的单位。
到目前为止,我有(显然不工作):
-- Normalize the quantities
select
sum( coefficient * quantity ) AS kilolitres
from
unit_conversion uc,
substance s
where
uc.unit = s.unit
group by
s.label
Run Code Online (Sandbox Code Playgroud)
这是否需要使用 log 10来确定位数?
这些单位并不都是十的幂。例如:http : //unitsofmeasure.org/ucum-essence.xml
这看起来很难看:
with uu(unit, coefficient, u_ord) as (
select
unit,
coefficient,
case
when log(u.coefficient) < 0
then floor (log(u.coefficient))
else ceil(log(u.coefficient))
end u_ord
from
unit_conversion u
),
norm (label, norm_qty) as (
select
s.label,
sum( uc.coefficient * s.quantity ) AS norm_qty
from
unit_conversion uc,
substance s
where
uc.unit = s.unit
group by
s.label
),
norm_ord (label, norm_qty, log, ord) as (
select
label,
norm_qty,
log(t.norm_qty) as log,
case
when log(t.norm_qty) < 0
then floor(log(t.norm_qty))
else ceil(log(t.norm_qty))
end ord
from norm t
)
select
norm_ord.label,
norm_ord.norm_qty,
norm_ord.norm_qty / uu.coefficient val,
uu.unit
from
norm_ord,
uu where uu.u_ord =
(select max(uu.u_ord)
from uu
where mod(norm_ord.norm_qty , uu.coefficient) = 0);
Run Code Online (Sandbox Code Playgroud)
但似乎可以解决问题:
| LABEL | NORM_QTY | VAL | UNIT |
-----------------------------------------
| mercury | 1.5e-8 | 15 | microlitre |
| water | 0.00112 | 112 | centilitre |
Run Code Online (Sandbox Code Playgroud)
您实际上并不需要表中的父子关系unit_conversion
,因为同一个系列中的单位自然会按照 的顺序相互关联coefficient
,只要您确定了系列即可。