Procurando calcular a unidade de medida mais adequada para uma lista de substâncias nas quais as substâncias são fornecidas em volumes unitários diferentes (mas compatíveis).
Tabela de conversão de unidades
A tabela de conversão de unidades armazena várias unidades e como essas unidades se relacionam:
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
A classificação pelo coeficiente mostra que parent_id
vincula uma unidade filho ao seu numérico superior.
Esta tabela pode ser criada no PostgreSQL usando:
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)
)
Deve haver uma chave estrangeira de parent_id
para id
.
Tabela de substâncias
A tabela de substâncias lista quantidades específicas de substâncias. Por exemplo:
id unit label quantity
1 "microlitre" mercury 5
2 "millilitre" water 500
3 "centilitre" water 2
4 "microlitre" mercury 10
5 "millilitre" water 600
A tabela pode se parecer com:
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)
)
Problema
Como você criaria uma consulta que encontre uma medida para representar a soma das substâncias usando o menor número de dígitos que possua um número inteiro (e opcionalmente componente real)?
Por exemplo, como você retornaria:
quantity unit label
15 microlitre mercury
112 centilitre water
Mas não:
quantity unit label
15 microlitre mercury
1.12 litre water
Como 112 tem menos dígitos reais que 1.12 e 112 é menor que 1120. No entanto, em certas situações, o uso de dígitos reais é menor - como 1,1 litro vs 110 centilitros.
Principalmente, estou tendo problemas para escolher a unidade correta com base na relação recursiva.
Código fonte
Até agora eu tenho (obviamente não trabalhando):
-- Normalize the quantities
select
sum( coefficient * quantity ) AS kilolitres
from
unit_conversion uc,
substance s
where
uc.unit = s.unit
group by
s.label
Ideias
Isso requer o uso do log 10 para determinar o número de dígitos?
Restrições
As unidades não são todas com potências de dez. Por exemplo: http://unitsofmeasure.org/ucum-essence.xml
fonte
Respostas:
Isso parece feio:
mas parece fazer o truque:
Você realmente não precisa da relação pai-filho na
unit_conversion
tabela, porque as unidades da mesma família estão naturalmente relacionadas entre si pela ordem decoefficient
, desde que a família seja identificada.fonte
Eu acho que isso pode ser bastante simplificado.
1.
unit_conversion
Tabela de modificaçãoOu, se você não pode modificar a tabela, basta adicionar a coluna
exp10
da "base do expoente 10", que coincide com o número de dígitos a serem deslocados no sistema decimal:2. Função de gravação
para calcular o número de posições para deslocar para a esquerda ou direita:
3. Consulta
Explicar:
f_shift_comma()
de cima.DISTINCT ON ()
eORDER BY
.COALESCE()
.-> Demonstração do SQLfiddle .
fonte