Лучший способ хранить единицы в базе данных

21

Я унаследовал большую (SQLServer) базу данных с сотнями столбцов, которые представляют суммы той или иной вещи. Единицы для этих значений (например, «галлоны», «дюймы» и т. Д.) Хранятся в поле MS_Description расширенных свойств. Мне интересно, есть ли лучший способ хранить эту информацию. Я предполагаю, что это хорошо для целей документирования, но было бы трудно сделать надежные вычисления преобразования единиц на основе этих данных. На данный момент я не готов внести инвазивные изменения, но если у меня появится возможность сделать это, какова рекомендуемая наилучшая практика в этом отношении? Варианты, в верхней части моей головы, могут включать в себя:

  • Измените имя столбца на включенные единицы (например, «TotalVolumeInGallons». Это сделает информацию немного более доступной, но она все еще кажется мне слабой.)
  • Добавьте отдельный столбец «Units», чтобы соответствовать каждому столбцу «Amount» (этот столбец может быть nvarchar ИЛИ это может быть внешний ключ к отдельной таблице Units, что может упростить вычисление конверсий единиц. С другой стороны, добавление так многие столбцы могут удвоить размер моей базы данных - с ужасно избыточными данными.)
  • Создайте новое поле в Extended Properties, предназначенное специально для юнитов. (К сожалению, я не думаю, что это может быть внешним ключом таблицы Units.)
  • Есть другая идея, которую я пропускаю?

ОБНОВЛЕНИЕ: после прочтения ответа @Todd Everett мне пришло в голову возможное решение, так что я собираюсь продолжить и ответить на мой собственный вопрос. (Увидеть ниже)

kmote
источник
Лучшая практика заключается в том, чтобы единая измерительная система использовалась универсально и последовательно во всем приложении. СИ будет система выбора. Значения в других системах будут преобразованы во время загрузки или в уровне представления, где каждый пользователь может выбрать свой предпочтительный набор.
Майкл Грин,

Ответы:

12

Поскольку вы упоминаете сотни столбцов, я бы рассмотрел дизайн EAV . Хотя Джо Селко предупреждает об этом , я думаю, что это может быть применимо в вашем случае использования. Похоже, что все ваши «суммы» являются числами, так что вы избежите проблем с приведением, которые описывает Джо, и необходимости превращать каждое «значение» в строку. Это будет работать даже лучше, если все суммы являются целыми числами, но может также работать, если некоторые являются десятичными. Учитывая единицы измерения, вы можете пойти еще дальше и реализовать модель стиля «универсальная модель данных», основанную на этой статье Дэвида Хэя, а также изложенную в его книге « Шаблоны моделей данных: условные обозначения»., Эта модель обладает дополнительным преимуществом настройки того, какие «суммы» применяются к каким «вещам», если вам это нужно. Один дополнительный шаг, показанный в книге на стр. 162, - это таблица преобразования единиц измерения, которую можно использовать для преобразования между различными единицами измерения. Вот пример:

UOM Conversion              

UOM From    UOM To        Cal Step  Operator Factor Constant
Kilograms   Pounds        1         *        2.2
Celsius     Fahrenheit    1         *        1.8
Celsius     Fahrenheit    2         +               32

Это говорит о том, что для преобразования из килограмма в фунт сначала нужно умножить килограмм на 2,2. Существует также константа, если преобразование должно также включать постоянное значение и возможность создавать несколько шагов. Таким образом, при преобразовании, скажем, в градусы Цельсия в градусы Фаренгейта вы умножаете градусы Цельсия на 1,8, а затем добавляете 32. Ключом будет значение от UOM, до UOM и шаг вычисления.

Это мои 2 цента. Я надеюсь, что эти ссылки дадут вам хорошую пищу для размышлений, если у вас когда-нибудь появится возможность перезагрузить текущий дизайн.

Тод эверетт
источник
Спасибо за очень интересную пищу для размышлений - я многому научился. Однако я не думаю, что EAV является подходящей моделью в моем случае (если я правильно понимаю ваше предложение), потому что, хотя у нас есть сотни столбцов, они ни в коем случае не редки. Тем не менее, этот DID породил связанную идею (см. ОБНОВЛЕНИЕ в моем оригинальном сообщении).
kmote
Ваша идея звучит довольно хорошо для меня - я не могу думать ни о каких других проблемах, кроме тех, которые вы уже указали. Но если столбцы могут быть переименованы / изменены, это будет проблемой в любом дизайне. Это когда сотрудничество весело - появляется идея, о которой никто из нас не думал с самого начала!
Тодд Эверетт
8

Все работают.

Обратите внимание, что во втором случае вы не можете добавлять яблоки и апельсины, и поэтому данные исключительно легко могут быть неправильно истолкованы.

Также обратите внимание, что преобразования не могут быть очень безопасными и подвержены ошибкам округления, переполнениям и т. Д.

Кроме того, существуют физические проблемы, такие как удельный вес и температура. Преобразование 20 галлонов воды в фунты потребует, чтобы вы знали плотность воды. Но плотность воды меняется в зависимости от температуры, поэтому вам может понадобиться либо узнать плотность одновременно с измерением, либо температуру аналогичным образом и использовать поправочный коэффициент объема.

В случае расширенных свойств это хорошо только для документации - хорошее имя столбца лучше для документации. Проблема с колонкой, подразумеваемой как находящаяся в фиксированной единице по имени, состоит в том, что вы в конечном итоге ставите себя в угол, когда меняете единицы измерения - новый клиент хочет масло в бочках, а не в галлонах - и это было бы хорошо, поскольку его данные находятся в его собственная база данных, но имя столбца в настоящее время вводит в заблуждение.

Другой вариант - хранить канонические версии в фиксированных единицах (то есть всегда в килограммах и метрах) в дополнение к различным исходным измерениям. Агрегатные операции с фиксированными единицами должны быть в порядке (за исключением того, что вы не добавите температуры, например), но вы не потеряете исходное измерение.

Кейд Ру
источник
1
Потенциальная «неверная интерпретация», о которой вы упоминаете, является как раз одной из проблем, с которыми я сталкиваюсь в связи с текущей архитектурой этой базы данных, и кое-что, что я пытаюсь найти способ уменьшить.
kmote
1
Важный момент о потенциальном недостатке решения с именем столбца.
kmote
1
@kmote Это не простая проблема - у нас есть отчеты, в которых отдельные транзакции могут иметь различные исходные единицы измерения, но также есть итоговое значение - то есть общее после преобразования в выбранную пользователем единицу измерения.
Cade Roux
7

Простое решение, которое хорошо работало для меня в прошлом, - хранить все ваши данные в «базовых» единицах. Например, ваша базовая единица измерения длины может составлять миллиметры, а базовая единица измерения веса - килограммы. Это решение может привести к необходимости преобразования некоторых существующих данных в базовый блок, если это еще не сделано.

Когда у вас есть все данные в стандартных базовых единицах, нет необходимости хранить единицу в самой базе данных, поскольку теперь это общесистемное предположение. Отображаемые единицы измерения, требуемые для каждого типа единиц (например, отображать ли длину в мм, дюймах, см, м), становятся проблемой приложения / клиентского домена, которую можно сохранить в локальном хранилище.

Таблицы преобразования единиц для преобразования между различными поддерживаемыми единицами могут быть жестко заданы в вашем приложении, поскольку новые единицы измерения изменяются крайне редко.

Обратите внимание, что решение, связанное с другой проблемой, заключается в том, что при хранении меток времени в базе данных их всегда нужно хранить в базовом блоке - UTC .

Еще один вопрос и ответ по теме ...

  • /programming/12977021/best-practice-for-storing-weights-in-a-sql-database

  • Здесь содержится некоторая полезная информация о том, почему использование типа столбца с плавающей запятой является наилучшим способом хранения реальных измерений.

dodgy_coder
источник
5

Поскольку любая единица может быть преобразована в другую единицу того же типа с помощью формулы:

y = ((x + xOffset) * multiplicand / denominator) + yOffset

Я хотел бы создать таблицу, которая содержит типы единиц плюс эти 4 значения.

From Unit     To Unit      Unit Type    From Offset    Multiplicand    Denominator    To Offset
'milligrams'  'grams'      'mass'       0              1               1000           0
'grams'      'kilograms'   'mass'       0              1               1000           0
'grams'      'ounces'      'mass'       0              100000          2835           0
'ounces'     'pound'       'mass'       0              1               16             0

После добавления всех измерений, которые вы, вероятно, хотите конвертировать, по обе стороны от списка, запустите запрос, в который вы вставляете обратную операцию, просто отменяя смещения и меняя множитель и знаменатель, а также на единицу измерения и единицу измерения.

Чтобы добавить преобразование между всеми типами, перекрестное соединение с некоторыми фильтрами может вставить остальные преобразования.

peroyhav
источник
3

После прочтения ответа @Todd Everett мне пришло решение, так что я собираюсь ответить и на свой вопрос. То , что я думаю , что я собираюсь сделать , это создать отдельную ColumnUnitsтаблицу с четырьмя столбцами: Schema, Table, Column, UnitsID(где UnitsID является FK в отдельную UnitsOfMeasureтаблицу), таким образом , отображение любого заданного столбца в связанной с ним единицы измерения. Очевидно, что самым большим недостатком этой идеи является то, что разработчики должны помнить, чтобы редактировать эту таблицу всякий раз, когда они переименовывают столбец или таблицу [ возможно, использовать триггер DDL ? ], иначе система сломается, Но если предположить, что такие переименования редки, а уровень разработки небольшой (в моем случае всего один человек), эта архитектура должна быть работоспособной. Преимущество состоит в том, что в текущую БД не нужно вносить инвазивные изменения, и мне нужно хранить значение только один раз для каждого столбца, а не один раз для строки, как того требует мой второй вариант в моем исходном сообщении.

kmote
источник
интересная головоломка ... и интересная идея у вас есть. Ваша идея упростит запрос, но, похоже, не многого достигнет. Вы только что переместили справочные данные в другое место. что беспокоит меня больше всего в этом дизайне
сэр Swears-A-
... в том, что если у элемента есть больше атрибутов, вам все равно нужно добавить больше столбцов. по этой причине мне нравится предложение @todd everett eav design.
Сэр, ругается много