Нормализация и исторические данные - PullRequest
1 голос
/ 13 октября 2010

Прежде чем я опишу свою проблему, я бы хотел увести пару вещей с пути:

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

Допустим, мы получаем электронную таблицу Excel раз в месяц из банка, но не всегда в одном и том же банке. Электронная таблица содержит всего шесть столбцов: название банка, номер счета, остаток на счете, имя клиента (владельца счета), SSN клиента и адрес владельца счета. У каждой строки есть свой номер счета, и номер счета не указан более чем в одной строке. Мы хотим импортировать эту электронную таблицу в базу данных и в любой момент в будущем сказать: «Какой адрес был у Джона Смита 13 октября 2010 года?»

Для простоты предположим, что у каждого клиента есть только один адрес, и что у каждого клиента может быть ноль или более учетных записей. И на секунду давайте представим, что нам нужно выполнить только один импорт листа Excel, КОГДА-ЛИБО, что является глупой предпосылкой, но терпите меня. Если это так, будет достаточно следующего дизайна:

bank
--------
id
name

account
--------
id
bank_id
customer_id
number
balance

customer
--------
id
name
ssn
address
city
state_id
zip

state
--------
id
name

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

Теперь, это было бы хорошо, если бы мы только когда-либо делали один импорт, но мы будем делать 12 импортов на банк в год. Вот как я думал об этом:

bank
--------
id
name

account
--------
id
import_id
bank_id
customer_id
number
balance

customer
--------
id
name
ssn
address
city
state_id
zip

state
--------
id
name

import
--------
id
date
excel_file (blob)

Теперь каждая учетная запись привязана к импорту, и мы можем с уверенностью сказать, что «Счет 12345 пришел из импорта 572 13.10.10». Потенциально становится немного более двусмысленным, когда вы смотрите, скажем, на таблицу customer. Поскольку в таблице customer меньше строк, чем в таблице account (поскольку у некоторых клиентов есть несколько учетных записей), у нас нет такого отношения один к одному между клиентами и импортом, как у нас для счетов и импорта , Я знаю, что нет потери данных и нет потери целостности данных, но это все равно похоже на какую-то жертву.

Мой вопрос (и это может быть слишком открытым): Как вы думаете, это хороший способ хранения данных? Вы сделали бы это по-другому?

Редактировать: есть важный способ думать об этих сущностях, о которых вы должны знать. Не думайте о account как об одной учетной записи, которая существует со временем. Представьте себе account как снимок учетной записи в определенный момент времени . Таким образом, счет 12345 с балансом $ 100 НЕ совпадает с account, как счет 12345 с балансом $ 150. Да, обе записи в реальном мире привязаны к одному и тому же банковскому счету, но я храню снимок учетной записи в определенный момент времени. Аналогичная (но не идентичная) ситуация с клиентами.

Ответы [ 6 ]

1 голос
/ 14 октября 2010

Понятия не имею, какую БД вы используете, но здесь говорится: я бы НЕ сохранил импорт как blob, так как он препятствует вашей способности связываться с вашими существующими данными, потому что вы должны обработать blob кактип файла, который вы ожидаете, прежде чем вы сможете присоединить его к любым другим вашим данным.Импортируйте данные прямо в таблицу импорта вместе с уже имеющимися полями идентификатора и даты.Поставьте key для идентификатора, затем unique compound index для даты, банка и счета, чтобы предотвратить дублирование в тот же день.

Если вы точно знаете, что у вас будет только 12 импортов в год (месяцев,Я полагаю?), Вы можете повысить целостность, создав два вычисляемых поля, одно для date_month (для хранения JUST месяца), а другое для date_year (для JUST года), а затем создать unique compound index для банковского идентификатора, счета, date_month и date_year.Это предотвратит случайный повторный импорт данных за тот же месяц в разные даты, например, если импорт за октябрь был выполнен в понедельник, то кто-то сделал это снова в вторник.Это также предотвратило бы сценарии «ой, я снова нажал кнопку» или «ой, я импортировал данные этого месяца как сценарии прошлого месяца».Чтобы ускорить проверки вычисляемых полей, поместите уникальные индексы в date_month и date_year.

Если вы хотите, чтобы ваша таблица клиентов всегда отображала текущий адрес без суеты, сделайте адрес вычисляемым полем, которое ищет вВаша таблица импорта по учетной записи клиента (или SSN или т. д.) и выбирает адрес TOP 1, отсортированный по дате DESC.Если вы хотите, чтобы запросы в адресном поле или включались в него были быстрее, поместите в него индекс.

1 голос
/ 13 октября 2010

Извините, я не могу согласовать утверждения «у каждого клиента только один адрес» и «мы хотим сказать,« каким был адрес Джона Смита 13 октября 2010 года »».Вы предлагаете, чтобы при каждом импорте вы создавали новую запись клиента для каждого человека, найденного в импорте?Если да, как вы узнаете, что Джон Смит в одном импорте - это тот же Джон Смит из другого импорта, если номера счетов отличаются?

И если вы повторно используете одну и ту же запись клиента для того же клиента (что кажется правильнымдля меня) где вы можете найти предшествующую информацию об адресе?

[После комментариев и поправок автора]

Хорошо, вы почти у цели.Вам нужно добавить адрес клиента в таблицу Account (которая должна быть переименована в AccountImports или что-то в этом роде).Это связано с тем, что у каждого импорта может быть свой адрес.

Сохранение адреса в AccountImports немного ненормально, если адрес часто остается неизменным от импорта к импорту.Если это так, вы можете добавить таблицу CustomerAddressHistory.Во время каждого импорта проверяйте последний адрес для SSN в CustomerAddressHistory и, если он отличается от импорта, добавляйте новый адрес в новую запись в этой таблице.

0 голосов
/ 14 октября 2010

Я бы создал новую таблицу с именем CustomerAddress и переместил бы информацию об адресе из клиента в эту новую таблицу

Затем в таблицу Account и таблицу CustomerAddress добавьте 2 новых столбца StartDate и EndDate

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

0 голосов
/ 13 октября 2010

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

Думаю также, что я бы не стал вносить import_id в аккаунт. Если вы сделаете это, вы получите много строк (х12) для каждого соединения клиента с банком. Не то, что вы хотите, я думаю. вместо этого вы можете поместить таблицу ссылок «учетная запись для импорта», чтобы сообщить, что эта учетная запись была указана в одном или нескольких из этих импортов.

0 голосов
/ 13 октября 2010

В общем, дизайн мне нравится.

Имеет ли сам import / import_id какое-либо значение помимо сохранения даты? Если нет, я не вижу причин, по которым вам не следует полностью исключать таблицу и помещать дату импорта import_date в таблицу учетных записей.

Кроме того, если вам нужна историческая информация об адресе, вам понадобится также import_id (или import_date :)) для таблицы клиентов.

Обновление

Как отмечено в комментарии, добавление import_id не будет учитывать исторические адресные данные.

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

customer
------
id
first_name
last_name (assuming name wouldn't change--it certainly could)


customer_history
-----------------
id
customer_id
import_id (or date)
(address fields)

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

0 голосов
/ 13 октября 2010
  1. Поскольку каждый импорт привязан к определенному банку, я мог бы рассмотреть вопрос о включении bank_id в таблицу импорта и исключении его из таблицы счетов.
  2. Если вы хотите учесть исторические адресные данные, и вы получаете эти данные исключительно из своих импортов, вы можете добавить поля адресов в таблицу счетов и удалить их из таблицы клиентов. Конечно, это может привести к дублированию, если у вас один и тот же адрес для нескольких импортов. Если вас это сильно волнует, вы можете добавить еще одну таблицу, возможно, «адрес», вероятно, с помощью составного первичного ключа customer_id и address_id. Затем ваша таблица импорта добавляет поле address_id, и ваш код импорта должен проверить, существует ли уже адрес.
...