2010-10-13 5 views
1

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

  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 на 10/13/10.» Это становится потенциально немного более неоднозначным, если вы посмотрите, скажем, на таблицу customer. Поскольку в таблице customer меньше строк, чем в таблице account (поскольку некоторые клиенты имеют несколько учетных записей), у нас нет такой индивидуальной связи между клиентами и импортом, как мы делаем для учетных записей и импорта. Я знаю, что нет потери данных, и нет потери целостности данных, но она по-прежнему кажется какой-то жертвой.

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

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

+0

При последовательном импорте, как вы решите вставить или обновить адрес клиента? Тебе все равно? –

+0

Очень хороший вопрос. Существует два способа: 1) создавать новые записи клиентов только в том случае, если что-то об изменениях клиента (например, имя или адрес) или 2) создавать новые записи клиентов каждый раз. Проблема, с которой я столкнулась, состоит в том, что я получаю дублирующиеся строки, что не так. –

+0

Еще один важный факт: NOTHING EVER обновляется (как в инструкции UPDATE) в этой базе данных. Другими словами, мы никогда не возвращаемся и не говорим: «О, в 2008 году адрес Джона Смита был фактически X» - это никогда не случается. Когда он находится, он остается тем, чем он является. –

ответ

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

1. Это, наверное, хорошая идея. 2. Поскольку каждый клиент имеет ровно один адрес, я не вижу причины разделять поля клиента и поля адреса на две таблицы. –

+0

@ Джейсон Свитт. Но вы заявляете: «Что было адресом Джона Смита 13 октября 2010 года?» как проблему для решения. Если адрес никогда не изменится, как бы вы это определили? – Andrew

+0

Хорошая точка.Вместо того, чтобы думать о каждой записи клиента как о фактическом клиенте, подумайте о клиенте как о снимке того, что было правдой об этом клиенте в определенный момент времени. То же самое со счетами. (Я отредактировал свой пост с некоторыми мыслями по этому поводу внизу.) Если вы подумаете об этом таким образом, у Джона Смита было бы 2 записи о клиентах, если он жил по 2 различным адресам. –

0

В целом дизайн выглядит хорошо для меня.

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

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

Update

Как отмечено в комментарии, добавив 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

Хороший улов. Я забыл, что хочу сохранить исходный файл Excel в таблице 'import'. Я отредактировал свой вопрос, чтобы исправить это. В противном случае вы правы, нет причин держать таблицу 'import' отдельной. –

+0

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

+0

Кроме того, если Джон Смит живет в 123 Fake St в импорте 100, то живет в 456 New St в импорте 101, он получит новую запись клиента. То же самое, если бы он изменил свое имя. Я думаю, что это связано с историческими данными. –

0

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

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

+0

Я собираюсь отдельно прокомментировать каждую проблему. Во-первых, вы правы, что клиенты могут иметь более одного адреса. Я сказал: «Для простоты, допустим, каждый клиент имеет только один адрес». В реальной жизни у клиентов может быть много адресов, но это сделало бы мой вопрос излишне сложным. Там много чего происходит, что я забыл. –

+0

Поскольку каждая учетная запись поступает только из одного импорта, я не понимаю, почему имеет смысл добавить таблицу для импорта. Если я хочу видеть, в каком банке (-ях) банка-клиенте есть все, что мне нужно сделать, это «SELECT b.name FROM customer c JOIN account a ON a.customer_id = c.id JOIN bank b ON a.bank_id = b. id WHERE c.name = 'John Smith''. Я не понимаю, что вы имеете в виду для множества строк для каждого соединения между клиентами. –

+0

ОК - я сделал предположение, что каждый месяц каждый день вы делаете счёт счетов, каждый из которых будет иметь дубликаты. Если это уже предварительно отфильтровано только для новых учетных записей, вы не должны ожидать дубликатов. Тем не менее, меня беспокоит сценарий «что-если», когда вы получаете больше одного, а также, что происходит, когда учетная запись закрыта? – Randy

1

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

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

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

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

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

+0

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

+0

Это очень хороший вопрос о том, как я расскажу, что Джон Смит из одного импорта такой же, как Джон Смит из другого. Мне придется подумать об этом. –

+0

В идеале у вас будет две таблицы: одна представляемая клиенту и другая, которая представляет собой привязку по времени. –

1

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

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

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

+0

Все это хорошие моменты. Blob предназначен только для отчетности, но не для поиска каких-либо данных. –

+0

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

+0

Может быть, не в тему, но поскольку мы говорим об исторических данных, если вы в конечном итоге хотите, чтобы данные были моими данными в этих блоках, то рано или поздно данные в этих x файлах за x месяцев в течение x лет все должны быть извлекается, очищается и консолидируется. Если банки на протяжении многих лет меняют форматы, у вас будет хороший кошмар для очистки данных на ваших руках. Просто говорю :) –

0

Я хотел бы сделать новую таблицу Called CustomerAddress и переместить адрес informaiton из клиента в новую таблицу

Тогда на счета таблицы и CustomerAddress стол добавить 2 новые столбцы StartDate и EndDate

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

Смежные вопросы