Раздвоение личности у клиента

Работа VB и СУБД (Access, MSSQL, MySQL, Oracle и пр.)
Правила форума
При создании новой темы не забывайте указывать используемую СУБД.
skiperski
Идеолог
Идеолог
Аватара пользователя
 
Сообщения: 1386
Зарегистрирован: 25.06.2002 (Вт) 15:52

Раздвоение личности у клиента

Сообщение skiperski » 13.04.2006 (Чт) 12:09

Расслабтесь, это не о том. :) Это об организации хранения данных о пользователе.

Имеем таблицу клиентов и кучу таблиц с нею связанных. Заказчик хочет чтобы можно было бы клиенту поменять адрес или название так, чтобы при этом его ID не изменился, но все старые документы были со старым адресом, а новые уже с новым. Задача осложняется тем, что уже есть куча связанных таблиц по ClientId и куча SQL-запросов. Если бы проектировалось с нуля было бы проще. У меня есть пара вариантов как это осуществить, но их пока не публикую, во-первых, чтобы ваши варианты не завязли в заранее намеченной колее стереотипов, и, во-вторых, просто нет времени, извините. :oops: Сейчас убегаю, буду часа через 3-4. Специально заранее пишу это сообщение, хоть и не развёрнуто как обычно, чтобы к моменту возвращения было что обсуждать. Надеюсь можно понять что требуется. И ещё: (опционально) придумать имя для таких вот дублей.

Спасибо за внимание.

ЗЫ: Надо бы уже какой-нибудь раздел типа "Проектирование" открывать.

GSerg
Шаман
Шаман
 
Сообщения: 14286
Зарегистрирован: 14.12.2002 (Сб) 5:25
Откуда: Магадан

Сообщение GSerg » 13.04.2006 (Чт) 12:15

Таблица истории изменения адресов: ClientID, Date, NewAddress.
Функция GetAddress(@ClientID int, @Date datetime).
Рефакторинг имеющихся запросов и замена в них Client.Address на GetAddress() (под словом "рефакторинг" в общем случае понимается в том числе и ручная замена).

При этом всём client.address оставить. И заменять потихоньку, оставляя систему рабочей в каждый момент времени...
Как только вы переберёте все варианты решения и не найдёте нужного, тут же обнаружится решение, простое и очевидное для всех, кроме вас

uhm
Продвинутый гуру
Продвинутый гуру
Аватара пользователя
 
Сообщения: 1597
Зарегистрирован: 02.12.2004 (Чт) 15:21

Сообщение uhm » 13.04.2006 (Чт) 12:26

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

Точно знаю, что в DataWarehouse нашего банка такая схема реализована.

ЗЫ По базам данных я далеко не специалист, так что на уровне идеи.
Быть... или не быть. Вот. В чём вопрос?

alibek
Большой Человек
Большой Человек
 
Сообщения: 14205
Зарегистрирован: 19.04.2002 (Пт) 11:40
Откуда: Russia

Сообщение alibek » 13.04.2006 (Чт) 13:17

Исторические записи лучше хранить в такой структуре: ID - NUMBER - START_DATE - END_DATE - ...
Здесь NUMBER (числовой) - порядковый номер записи; поле это редактируются автоматом. Можно также добавить флаг LAST, указывающий, что поле является последним.
По сравнению с ID - DATE - ... будет намного проще составлять запросы.
Lasciate ogni speranza, voi ch'entrate.

skiperski
Идеолог
Идеолог
Аватара пользователя
 
Сообщения: 1386
Зарегистрирован: 25.06.2002 (Вт) 15:52

Сообщение skiperski » 13.04.2006 (Чт) 14:15

Как-то я быстрее обернулся чем ожидал. Який я швыдкий!

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

1. Отдельная таблица, где хранится история изменения клиента. Нечто вроде предложенного GSerg'ом, uhm'ом и alibek'ом. Поиск либо по дате, либо по минорному ID. В качестве контроля актуальной записи, либо Disabled для старых записей, либо, как предлагал alibek, Last - для актуальной. Испугало внедрение функции поиска нужной записи в каждый запрос, тем более что это в Access'е. Когда-то делал похожее на FoxPro, тормозило жутко. А при поиске по минорному УИН'у, ещё придётся во всех связанных таблицах хранить доп. столбец.

2. То же самое, но в одной таблице. Добавляется одно поле как у alibek' а и включается в составной PrimaryKey. Тупо копируется запись о клиенте с тем же ID, кроме даты создания, инкрементируется минорный ID и на не актуальные записи ставится Disabled. Недостатки те же что и с отдельной таблицей.

3. Далее были различные вариации на эту тему, но они не стоят отдельного описания.

А вот пока путешествовал придумал следующее (кстати, как вы думаете?). Добавляем новое поле, но не включам его в PrimaryKey. Копируем в него текущие значения ID. При создании новой записи просто берём значение ID. При изменении данных клиента создаём клон записи: т.е. копируем всё кроме даты создания (устанавливаем новую). В исходной записи устанавливаем флаг что-нибудь типа Cloned и в списке клиентов она не отображается и все новые документы будут привязаны уже к клону клиента без изменения логики программы. Т.о. клон будет иметь собственный ID и плюс ID клонированной записи. Все запросы по всязанным таблицам остаются прежними. Остаётся только при выводе на экран подставлять не настоящий ID, а второй и при поиске, может быть, искать также ID клона. Мне пока этот вариант нравится больше всего. Поковыряйте его, пожалуйста, может где какие подводные камни есть?

Andrey Fedorov
Член-корреспондент академии VBStreets
Член-корреспондент академии VBStreets
 
Сообщения: 3287
Зарегистрирован: 21.05.2004 (Пт) 9:28
Откуда: Москва

Сообщение Andrey Fedorov » 13.04.2006 (Чт) 16:29

Просто сохранять адрес (и прочие реквизиты) в самих документах.
Несколько избыточно но зато просто.

Правда при редактировании документа возникает вопрос: а что делать с реквизитами? Но он возникнет при любом из способов...
Фиг Вам! - Сказал Чебурашка, обгладывая Крокодила Гену...

skiperski
Идеолог
Идеолог
Аватара пользователя
 
Сообщения: 1386
Зарегистрирован: 25.06.2002 (Вт) 15:52

Сообщение skiperski » 14.04.2006 (Пт) 0:32

Отсутствие критики позволяет считать, что в предложенном мною методе всё идеально. :D В общем-то идея лежит на поверхности, но мы часто за деревьями леса не видим.

2 Andrey Fedorov:
Документов вообще как таковых нет. Они формируются каждый раз по запросу. Если пройдёт идея с клиентами, то распространю её и на шаблоны и на цены товаров.

gaidar
System Debugger
System Debugger
 
Сообщения: 3152
Зарегистрирован: 23.12.2001 (Вс) 13:22

Сообщение gaidar » 14.04.2006 (Пт) 18:07

Не совсем понял идею skiperski, но скажу, как сделано у меня:

Допустим есть таблица Customers с тремя десятками полей, есть поле CustomerID и поле ParentID. Так вот записей может быть угодно, но всегда есть самая первая, которая называется Master Record в моей терминологии. А есть Slave Records.
При изменении Master Record или Slave Record создается еще одна Slave с соответствующим Parent ID. Т.е. в таблице один Master и сколько угодно Slave на него указывающих. При удалении Master записи, срабатывает триггер, который вычищает все данные для Slave. Собственно и при изменении записи срабатывает триггер, который создает новую и для клиента (вызывающего кода) все прозрачно, он вообще не знает, какую запись меняет. Можно обойтись и без даты, сортируя по ID.

Похоже, чт сам skiperski это же и предложил, только менее развернуто :). Кстати, очень рекомендую использовать триггеры и дополнительный уровень абстракции.
The difficult I’ll do right now. The impossible will take a little while. (c) US engineers in WWII
I don't always know what I'm talking about, but I know I'm right. (c) Muhammad Ali

skiperski
Идеолог
Идеолог
Аватара пользователя
 
Сообщения: 1386
Зарегистрирован: 25.06.2002 (Вт) 15:52

Сообщение skiperski » 14.04.2006 (Пт) 18:41

gaidar писал(а):Похоже, чт сам skiperski это же и предложил, только менее развернуто :).

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

Кстати, побочный положительный эффект: можно дополнительные ID трактовать как человеко понятный номер и сделать редактируемыми самими пользователями.

gaidar писал(а):Кстати, очень рекомендую использовать триггеры и дополнительный уровень абстракции.

А в Access триггеры есть? И о доп. уровне, пожалуйста, подробнее. Я знаю что это такое, но, как часто бывает, трактовка одних и тех же терминов может существенно различаться.

gaidar
System Debugger
System Debugger
 
Сообщения: 3152
Зарегистрирован: 23.12.2001 (Вс) 13:22

Сообщение gaidar » 17.04.2006 (Пн) 0:05

В Access триггеров нет.

Доп. уровень - это когда твой код обращается к табличке Users, а триггер понимает твою бизнес-логику и делает нужные update/insert/delete/select в нужных таблицах.
Например, ты вставляешь данные в таблице Persons, а триггер ее пихает в Customers, или в Employees. Соответственно ты работаешь одинаково с таблицой Persons, а на самом деле есть две большие разницы, даже поля могут по разному заполнятся.
The difficult I’ll do right now. The impossible will take a little while. (c) US engineers in WWII
I don't always know what I'm talking about, but I know I'm right. (c) Muhammad Ali

skiperski
Идеолог
Идеолог
Аватара пользователя
 
Сообщения: 1386
Зарегистрирован: 25.06.2002 (Вт) 15:52

Сообщение skiperski » 24.04.2006 (Пн) 13:00

Спасибо, gaidar, за объяснения. Какие-то уровни абстрагирования в этой программе были применены, но не такие глубокие.

В общем и целом этот метод оказался самым низкозатратным. Практически многие запросы совсем не поменялись, во многих заменил лишь ClientId на ClientNumber и лишь изредка пришлось заметно править. Есть некоторая путаница когда какой номер выдавать, но это проблемы соглашения и не ясного понимая (мною) всей перспективы данного решения.

Теперь сопутствующий вопрос по интерфейсу. Напоминаю, что это - веб-приложение.

По поводу прозрачности: логично не давать пользователю повода думать, что он работает с разными записями, а не с одной. Но тогда получается, что на каждое изменение основных данных создаётся новая запись. А если нужно было только исправить грамматическую ошибку? И где искать старый адрес клиента, который уже выбыл из списков?

Если отказываться от прозрачности, то какая последовательность действий была бы лучше?

1. Спрашивать чего хочет делать исправить ошибку или клонировать запись перед редактированием.

2. Спрашивать уже в диалоге редактирования или при попытке внести изменения.

ЗЫ: кстати, я подумал, что эту тему можно было бы перенести в "Базы данных"

Ennor
Конструктивный критик
Конструктивный критик
 
Сообщения: 2504
Зарегистрирован: 18.12.2001 (Вт) 3:58
Откуда: Калуга -> Москва

Сообщение Ennor » 24.04.2006 (Пн) 16:26

skiperski писал(а):Но тогда получается, что на каждое изменение основных данных создаётся новая запись.
Да. Именно так.
Все вопросы, почему именно так, исчезнут при первом же вопле "Кто поменял?!!..." одного из операторов. Или начальства, что еще хуже.

skiperski
Идеолог
Идеолог
Аватара пользователя
 
Сообщения: 1386
Зарегистрирован: 25.06.2002 (Вт) 15:52

Сообщение skiperski » 24.04.2006 (Пн) 17:24

То что при клонировании добавляется новая запись - понятно. Вопрос в том, что само клонирование бэкграундом не всегда оправдано.

Например, кто-то ввёл адрес с ошибкой, просто грамматической ошибкой. Например, город "ПопробЫвал", улица "ИзвЕняюсь". Или при наборе смешал русские и латинские алфавиты так, что видимых ошибок нет, но поиск не работает. Уже после создания документов кто-то более грамотный или внимательный обращает внимание на это. При клонировании появятся две записи - правильная и предыдущая ошибочная - и во всех старых документах будут кривые имена/адреса, тогда как можно было бы преспокойно оставить одну запись с уже новыми значениями, т.к. ни на что существенное они не влияют. Собственно адрес не поменялся, его лишь подправили или уточнили (добавили номер корпуса, поставили кавычки в имени фирмы и т.п.). И вот тут пользователя надо спросить что же он собирается сделать: исправить ли ошибку с отображением на все уже созданные документы или кардинально изменить данные клиента.

ЗЫ: а "кто поменял" можно хранить в логах.

alibek
Большой Человек
Большой Человек
 
Сообщения: 14205
Зарегистрирован: 19.04.2002 (Пт) 11:40
Откуда: Russia

Сообщение alibek » 25.04.2006 (Вт) 7:28

Нет, Ennor прав, надо всегда добавлять новую запись. Ошибки ввода -- это проблемы операторов. А если уж будет крайний случай, то на этот случай есть админ с доступом к БД. Или какое другое доверенное лицо с доступом к админ-консоли на web-интерфейсе.
Lasciate ogni speranza, voi ch'entrate.

skiperski
Идеолог
Идеолог
Аватара пользователя
 
Сообщения: 1386
Зарегистрирован: 25.06.2002 (Вт) 15:52

Сообщение skiperski » 25.04.2006 (Вт) 9:27

Хм, права на изменение таких данных и так далеко не у многих, а вот право на ошибку имеют все. :) Например ввели в адресе не верный номер дома. Составили договор, при подписании не заметили. Позже клиенту отправили второй экземпляр или уведомление или новый заказ и т.п. Соответственно он его либо не получил, либо получил с исправлениями почты, либо нашёл лежащим на соседнем ящике. Отзванивается. Оператор меняет адрес. Получаем в результате все предыдущие документы (не бумажные, с ними понятно - остаются как есть, а генерируемые) с ошибочным адресом. Т.о. в случае не получения клиентом письма его нужно будет составить заново и хорошо если письмо это одно, а не десяток счетов с пятьюдесятью пятью позициями заказов в каждом. Или документы тоже нужно будет клонировать? Это было раз.

Два. Пусть только админ может менять с отображением на все старые документы. Тогда ему всё-равно необходимо задать вопрос какое действие он хочет выполнить. Так что вопрос остаётся в силе: как более логично организовать интерфейс выбора действия.

alibek
Большой Человек
Большой Человек
 
Сообщения: 14205
Зарегистрирован: 19.04.2002 (Пт) 11:40
Откуда: Russia

Сообщение alibek » 25.04.2006 (Вт) 9:36

Оператор, допустивший ошибку, лишается части премии и в следующий раз будет внимательнее :)
А у админа возможность конечно будет, но у него и интерфейс будет другой. Либо кнопка "Откорректировать запись", либо он будет напрямую в БД менять.
Lasciate ogni speranza, voi ch'entrate.

skiperski
Идеолог
Идеолог
Аватара пользователя
 
Сообщения: 1386
Зарегистрирован: 25.06.2002 (Вт) 15:52

Сообщение skiperski » 25.04.2006 (Вт) 12:28

Какой ты, alibek, однако, кровожадный! :spiderman: Чуть что - сразу бан. Терпимее надо быть, толерантнее. :)

Всёж-таки кнопка нужна. Напрямую нефиг в базу лазить. И так эта прога трещит по всем швам. И всё же: сначала кнопка - потом правка или сначала правка - потом кнопка?

alibek
Большой Человек
Большой Человек
 
Сообщения: 14205
Зарегистрирован: 19.04.2002 (Пт) 11:40
Откуда: Russia

Сообщение alibek » 25.04.2006 (Вт) 13:05

Нормальный режим (с созданием записи в истории): изменение полей, нажатие кнопки "Сохранить".
Режим корректировки: кнопка "Корректировать", изменение полей, нажатие кнопки "Сохранить".
Lasciate ogni speranza, voi ch'entrate.


Вернуться в Базы данных

Кто сейчас на конференции

Сейчас этот форум просматривают: SemrushBot и гости: 1

    TopList