standard solution for storing units of measure

Assuming that measurement types will not be mixed (i.e. any particular row will not mix "kg" and "inches" OR "pounds" and "cm"), and also assuming that at least part of the intention of this Question relates to this now deleted related Question (please note that the following link will not work unless you have enough rep points to see deleted items: Handling composite attributes with constant part ), then you need only to indicate the system of measurement being used by that row. In this model, you would have a single MeasurementSystem table that is Foreign Keyed to any tables containing measurements. For example (using Microsoft SQL Server syntax):

CREATE TABLE dbo.MeasurementSystem
(
  MeasurementSystemID TINYINT NOT NULL
                      CONSTRAINT [PK_MeasurementSystem] PRIMARY KEY
                                 CLUSTERED,
  MeasurementSystemName NVARCHAR(50) NOT NULL
);

dbo.Person
(
  PersonID            INT NOT NULL IDENTITY(1, 1)
                      CONSTRAINT [PK_Person] PRIMARY KEY
                                 CLUSTERED,
  MeasurementSystemID TINYINT NOT NULL
                      CONSTRAINT [FK_Person_MeasurementSystem]
                      FOREIGN KEY
                      REFERENCES dbo.MeasurementSystem (MeasurementSystemID),
  Name                NVARCHAR(50) NOT NULL
  Height              FLOAT,
  Weight              FLOAT,
  ...
);

INSERT INTO dbo.MeasurementSystem (MeasurementSystemID, MeasurementSystemName)
VALUES (1, N'Metric');

INSERT INTO dbo.MeasurementSystem (MeasurementSystemID, MeasurementSystemName)
VALUES (2, N'United States customary units');

If you will be mixing measurement systems and/or if you will be allowing for multiple units of measurement even if confined to one system (i.e. allowing for "mm", "cm", "m"), then there will need to be an additional layer to handle the increase in granularity, including the need to have one FK field per each measure column in the Person table. (I can adapt the model above to fit this but will wait for some clarification before doing so).


Or, if there will be a fairly finite / limited amount of combinations of various weight units and height units, then you can instead use each row to represent one of the accepted combinations (e.g. "cm & kg", "m & kg", "mm & kg" / "inch & lb", "foot & lb"). And then "US" vs "Metric" is just a property of each row of the lookup table. For example:

CREATE TABLE dbo.MeasurementUnit
(
  MeasurementUnitID     TINYINT NOT NULL
                                CONSTRAINT [PK_MeasurementUnit] PRIMARY KEY
                                           CLUSTERED,
  MeasurementSystem     CHAR(1) NOT NULL, -- "M" = Metric, "U" = US 
  MeasurementSystemName NVARCHAR(50) NOT NULL, -- "Metric" or "US Nonsense"
  HeightUnitsName       NVARCHAR(20) NOT NULL, -- "Centimeters"
  HeightUnitsAlias      NVARCHAR(5) NOT NULL, -- "cm"
  WeightUnitsName       NVARCHAR(20) NOT NULL, -- "Kilograms"
  WeightUnitsAlias      NVARCHAR(5) NOT NULL -- "kg"
);

dbo.Person
(
  PersonID            INT NOT NULL IDENTITY(1, 1)
                      CONSTRAINT [PK_Person] PRIMARY KEY
                                 CLUSTERED,
  MeasurementUnitID   TINYINT NOT NULL
                              CONSTRAINT [FK_Person_MeasurementUnit]
                                         FOREIGN KEY
                                        REFERENCES dbo.MeasurementUnit (MeasurementUnitID),
  Name                NVARCHAR(50) NOT NULL
  Height              FLOAT,
  Weight              FLOAT,
  ...
);

Or, if there needs to be combinations of Units that cross different measurement systems, then I would use separate tables -- one for each measurement type: "WeightUnits" and "HeightUnits". I wouldn't mix units for heights & weights in the same table (i.e. "kg" and "cm" on different rows). For example:

CREATE TABLE dbo.WeightUnit
(
  WeightUnitID      TINYINT NOT NULL
                            CONSTRAINT [PK_WeightUnit] PRIMARY KEY
                                       CLUSTERED,
  MeasurementSystem CHAR(1) NOT NULL, -- "M" = Metric, "U" = US 
  WeightUnitName    NVARCHAR(50) NOT NULL, -- "Kilograms"
  WeightUnitAlias   NVARCHAR(5) NOT NULL -- "kg"
);

CREATE TABLE dbo.HeightUnit
(
  HeightUnitID      TINYINT NOT NULL
                            CONSTRAINT [PK_HeightUnit] PRIMARY KEY
                                       CLUSTERED,
  MeasurementSystem CHAR(1) NOT NULL, -- "M" = Metric, "U" = US 
  HeightUnitName    NVARCHAR(50) NOT NULL, -- "Centimeters"
  HeightUnitAlias   NVARCHAR(5) NOT NULL -- "cm"
);

In this model, each measurement type in any given table has its own personal FK to its measurement units lookup table.


Seeing as how this question is in regard to design, the answers are likely to be fairly opinionated...

Here is my opinion on how it should be designed. ;)

Table to store units of measure

CREATE TABLE measure_unit (
  measure_unit_id, -- primary key
  name -- unique key .. values such as "inch" etc
)

Your person table ...

CREATE TABLE person (
  person_id, -- primary key
  name,
  measurement, -- example values would be 180
  measure_unit_id -- example values would be the pkey for centimeters
)

And then a conversion table

CREATE TABLE measure_conversion (
  from_measure_unit_id, -- example would be pkey for centimeters
  to_measure_unit_id, -- example would be pkey for inches
  ratio -- example would be 0.393701 (centimeters * 0.393701 = inches)
  -- pkey is composite between both from and to values
)

If a unit of measure doesn't have an entry in the measure conversion table for a specific other type of unit, then there would be no direct conversion available. (For example, cm -> inches would work, but cm -> hours wouldn't..) Displaying your measurements in different units should be easy.

Your measure unit can be anything you want (distance/time/etc) ... but you may want to add a measurement type .. not sure if I'd worry about that - depends on use case.


If your height/weight measure-units are indeed fixed, i.e. height=CMs, Weight=KGs, I would not introduce any additional columns (or logic) to specify the unit of measure. Instead, what I would do is just change the column name such as

create table Person (ID int, Name varchar(50), Height_CM double, Weight_KG double)

This way, I can remove any confusions about the measure unit for Height and Weight columns.