Buscando calcular la unidad de medida más adecuada para una lista de sustancias donde las sustancias se administran en volúmenes de unidades diferentes (pero compatibles).
Tabla de conversión de unidades
La tabla de conversión de unidades almacena varias unidades y cómo se relacionan esas unidades:
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
Ordenar por el coeficiente muestra que parent_id
vincula una unidad secundaria a su superior numérico.
Esta tabla se puede crear en 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)
)
Debe haber una clave foránea de parent_id
a id
.
Tabla de sustancias
La tabla de sustancias enumera cantidades específicas de sustancias. Por ejemplo:
id unit label quantity
1 "microlitre" mercury 5
2 "millilitre" water 500
3 "centilitre" water 2
4 "microlitre" mercury 10
5 "millilitre" water 600
La tabla podría parecerse a:
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
¿Cómo crearía una consulta que encuentre una medida para representar la suma de las sustancias utilizando la menor cantidad de dígitos que tenga un número entero (y opcionalmente un componente real)?
Por ejemplo, ¿cómo regresarías?
quantity unit label
15 microlitre mercury
112 centilitre water
Pero no:
quantity unit label
15 microlitre mercury
1.12 litre water
Debido a que 112 tiene menos dígitos reales que 1.12 y 112 es menor que 1120. Sin embargo, en ciertas situaciones, el uso de dígitos reales es más corto, como 1.1 litros frente a 110 centilitros.
Principalmente, tengo problemas para elegir la unidad correcta en función de la relación recursiva.
Código fuente
Hasta ahora tengo (obviamente no funciona):
-- Normalize the quantities
select
sum( coefficient * quantity ) AS kilolitres
from
unit_conversion uc,
substance s
where
uc.unit = s.unit
group by
s.label
Ideas
¿Requiere esto usar el registro 10 para determinar la cantidad de dígitos?
Restricciones
Las unidades no están todas en potencias de diez. Por ejemplo: http://unitsofmeasure.org/ucum-essence.xml
fuente
Respuestas:
Esto se ve feo:
pero parece hacer el truco:
Realmente no necesita la relación padre-hijo en la
unit_conversion
tabla, porque las unidades de la misma familia están naturalmente relacionadas entre sí por orden decoefficient
, siempre y cuando haya identificado a la familia.fuente
Creo que esto se puede simplificar en gran medida.
1. Modificar
unit_conversion
tablaO, si no puede modificar la tabla, simplemente agregue la columna
exp10
para "exponente base 10", que coincide con el número de dígitos que se desplazarán en el sistema decimal:2. Función de escritura
para calcular el número de posiciones para desplazarse hacia la izquierda o hacia la derecha:
3. Consulta
Explique:
f_shift_comma()
desde arriba.DISTINCT ON ()
yORDER BY
.COALESCE()
.-> Demostración SQLfiddle .
fuente