Предлагаемая схема БД для заявления на возмещение расходов на обед - PullRequest
1 голос
/ 09 марта 2011

Я занимаюсь разработкой веб-приложения для смартфонов с помощью jqTouch. Идея в том, чтобы уметь:

  • Отслеживать, кто кому должен обед
  • Отслеживание долга с течением времени
  • Передача долга от одного человека другому

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

Jason buys lunch for David
David buys lunch for Roslyn
Phillip buys lunch for Roslyn

Итак - Дэвид должен Джейсону, Рослин должен Дэвиду и Филиппу. В качестве урегулирования задолженности Дэвид компенсирует свой долг Джейсону, и Рослин покупает ему обед в качестве компенсации Дэвиду, и теперь они равны. Единственный человек, который остался на ногах, это я, и это вполне нормально для курса:)

Реальный вопрос ...

Как я могу выразить это в терминах реляционных БД? Я могу отслеживать расходы и пользователей по отдельным позициям:

purchases
=========
purch_id
user_id
amount
location

users
=======
user_id
name

Обращаюсь ли я с остальным как с бизнес-логикой? Как я могу отследить долг? Если бы я хотел получить из этого содержательные отчеты, такие как расходы во времени и среднее время, которое требуется конкретному человеку для погашения - мне нужна более сложная схема!

Любые мысли / критика приветствуются! Это забавное умственное упражнение, которое никоим образом не считается серьезным проектом.

Обновление

Учитывая отсутствие интереса к поставленному вопросу - я отправляю награду! Вот некоторые вопросы, которые необходимо будет решить для получения награды:

  • Как отслеживать промежуточные итоги, не суммируя потенциально длинную таблицу транзакций
  • Как отслеживать метаданные для транзакций без чрезмерной нормализации (например, описанная выше функция «условной задолженности»

Ответы [ 5 ]

2 голосов
/ 17 марта 2011

Предлагаемый вами план звучит хорошо ... Начните со следующих отношений для отслеживания людей и транзакций:

 Person(*PID*, Name)  

Где PID - это суррогатный ключ для уникальной идентификации каждого человека.

 Transaction(*TID*, Description, Date)  

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

Отслеживание того, кто должен кому:

 Owes(*PIDOwes*, *PIDOwed*, *TID*, Amount)  

Где PIDOwes и PIDOwed являются идентификаторами, из которыхЧеловек отношения.TID идентифицирует транзакцию, ответственную за создание дебета, и ее сумму.

Каждый раз, когда группа отправляется на ланч, создается новая Транзакция, и отношение Owes обновляется, чтобы отразить, кто в результате должен кому.Так будет выглядеть ваша база данных после того, как Джейсон купит Дэвиду обед в 15.00;Дэвид покупает Рослин обед на 10.00, а Филипп покупает Рослин обед на 12.00.Предположим, что стоимость обеда разделена на 50:50 (вы можете разделить ее по своему усмотрению. Важный бит - это то, что дебет назначается каждому человеку):

Person(J, Jason)
Person(D, David)
Person(R, Roslyn)
Person(P, Phillip)

Transaction(1, Lunch, 2011-03-04)
Transaction(2, Lunch, 2011-03-05)
Transaction(3, Lunch, 2011-03-06)

Owes(D, J, 1, 7.50)
Owes(R, D, 2, 5.00)
Owes(R, P, 3, 6.00)

Переключение на дебет:

Когда Дэвид переводит дебет Рослина Джейсону, вы записываете следующие транзакции:

Transaction(4, CommuteDebit, 2011-03-07)

Owes(R, J, 4,  5.00)
Owes(R, D, 4, -5.00)

Может быть разумно проверить, что Рослин действительно должна Дэвиду как минимум 5,00, прежде чем принять эту транзакцию!

Вторая строка Owes, приведенная выше, могла быть записана как David задолжал Roslyn 5.00, но мне нравится метод +/-, поскольку он отражает идею о том, что это транзакция с нулевой суммой.Еще одним преимуществом является то, что вы можете определить, кто инициировал коммутируемый дебет, потому что они всегда будут PIDOwed в строке Owes с отрицательной суммой.

Следующая транзакция создается, когда Roslyn поднимает вкладку для части обеда Джейсона.стоит 13.00 сплит 50: 50:

Transaction(5, Lunch, 2011-03-08)

Owes(J, R, 5, 6.50)

Внезапно все усложняется ... Взаимные дебиты накапливаются.Дэвид должен Рослин, а Рослин должен Дэвид.Эти дебеты должны компенсировать друг друга так, что Дэвид должен Рослин 1,50.Отношение к долгу заключается в том, что, за исключением дебетовых поездок, суммы только накапливаются.Получение баланса достигается путем взаимозачета всех «A» задолженностей «B» из «B» задолженностей «A».Отношение Owes - это запись сведений о транзакции, она не предоставляет текущих сальдо.

Запрос для расчета сальдо для 'Jason owes Roslyn' довольно прост и выглядит примерно так:

select sum(case when PIDOwes = 'J' then
                     +amount
                else
                     -amount
                end)
from Owes
where PIDOwes in ('R', 'J')
  and PIDOwed in ('J', 'R')

Этот запрос вернет 1.50 - сумма, которую Джейсон теперь должен Рослин.

Чтобы узнать, кому Рослин следует в следующий раз угостить обедом, получается путем итерации вышеупомянутого запроса по таблице Person, заменяющей 'J' на каждой итерации (Рослин остается постоянной).Когда сумма положительная, Рослин должна.Когда сумма отрицательная, этот человек должен Рослин.

Такой запрос приведет к:

Phillip  6.00
Jason   -1.50

Итак, Рослин должна относиться к Филиппу, а Джейсон должен относиться к Рослин.

Расчет общего баланса для отдельного человека, например, Дэвида, будет сделан путем суммирования всех строк Owes, имеющих David в качестве PIDOwes, и вычтения их из суммы строк, в которых David является PIDOwed.

Основная проблемас этой схемой вы должны суммировать по всему отношению Owes, чтобы получить сальдо.Возможная деморализация для оптимизации может состоять в том, чтобы поддерживать отношение Баланс, например:

 OwesBal(*PIDOwes*, *PIDOwed*, Balance)

Каждый раз, когда в запись отношения Owes добавляется строка, которая A должна B некоторой суммой, отношение OwesBal обновляется следующим образом:

set TranAmt to whatever A owes B according to the new Owes row.

select Balance as AowesB
from OwesBal
where PIDOwes = 'A'
  and PIDOwed = 'B'

select Balance as BowesA
from OwesBal
where PIDOwes = 'B'
  and PIDOwed = 'A'

if BowesA < TranAmt then
   TranAmt = TranAmt - BowesA
   BowesA = 0.00
else
   BowesA = BowesA - TranAmt
   TranAmt = 0.00

update OwesBal
set Balance = BowesA
where PIDOwes = 'B'
  and PIDOwed = 'A'

update OwesBal
set Balance = Balance + TranAmt
where PIDOwes = 'A'
  and PIDOwed = 'B'

Конечно, вам нужно отследить «не найденные» условия и создать начальные строки OwesBal при появлении новых комбинаций обеденных партнеров.

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

 Share(*PID*, *TID*, Amount)

Отношение Share будет заполняться во время заполнения отношений Transaction и Owes.Каждый человек будет входить в свою долю.Например:

Share(D, 1, 7.50)
Share(J, 1, 7.50)
Share(R, 2, 5.00)
Share(D, 2, 5.00)
Share(R, 3, 6.00)
Share(P, 3, 6.00)
Share(J, 5, 6.50)
Share(R, 5, 6.50)

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

1 голос
/ 17 марта 2011

Интересная проблема - давайте сделаем некоторые предположения.

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

Все обеды имеют одинаковое значение - мы предполагаем, что единицей измерения является «обед», а не «деньги».Итак, вы покупаете мне обед в «Ритце», я покупаю вам обед в «Макдоналдсе», и мы в порядке.

Единственный способ оплатить долг - это купить обед.Нет наличного способа сорваться с крючка и нет способа «отказаться» от долга.

Когда ты должен мне 3 ланча, а потом купишь мне один ланч, нет прямой связи между ланчем, который ты мне покупаешь, и тем, что ты мне должен - ланчом можно назвать смешным.

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

Моя схема предложения будет выглядеть примерно так:

**User**
user_id pk
name

**lunch**
lunch_id pk
date

**transaction**
transaction_id pk
user_id
value
lunch_id

Таким образом, когда я покупаю вам обед, мы создаем новую запись в таблице "обедов" и вставляем транзакцию с вашим идентификатором пользователя, значением "-1" и ссылкой на идентификатор обеда.,Мы также создаем для меня транзакцию со значением «+1».

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

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

1 голос
/ 14 марта 2011

Вы можете использовать макет, предложенный dleavitt, и объединить поля lunch_id, creditor_id, debtor_id и amount в качестве Первичного ключа. Это позволит вам добавить еще одну строку, используя тот же lunch_id, пока хотя бы одно из других полей изменяет значения. Это означает, что вы можете добавить строку с тем же обеденным идентификатором и просто изменить creditor_id, чтобы заменить этот обед кому-то еще. Точно так же вы можете изменить debtor_id в новой строке, чтобы переместить долг от одного человека другому. С помощью этой настройки вы также можете реализовать частичные платежи, добавив новую строку и введя отрицательные значения для обозначения платежей. Добавление этих сумм даст мне промежуточную сумму задолженности. Этого должно быть достаточно для отслеживания изменений и сохранения исторических данных. Возможным дополнением может быть поле даты и времени, чтобы проверить, когда была вставлена ​​новая строка. Добавление этого поля к Первичному ключу также решает ситуацию, когда кто-то переводит долг в долг, а затем он возвращается к первоначальному кредитору. Здесь новая строка будет иметь другое значение даты и времени, поэтому оно будет действительным. enter image description here

0 голосов
/ 16 марта 2011

Я работаю в банке, и я думаю, что наиболее подходящей для вас системой является создание системы, основанной на некоем кредите.Я не уверен, имеет ли значение цена обеда к вопросу.Supose друг купил вам прекрасный кусок пирога с экзотическими фруктами.И ты купил ему / ей МакЧикен.Это тот же долг?Независимо от ситуации (цена обеда имеет значение или нет), кредитная система должна быть хорошей вещью.Я собираюсь разработать столы, способные работать, полагая, что некоторые обеды более ценны, чем другиеВ противном случае, учитывайте только один кредит на весь обед.

t001_partners
prt_id: bigInt
prt_name: string
prt_balance: int

t002_lunch
lnc_id: bigInt
lnc_description: string
lnc_store: string
lnc_credits: int

t003_lunch_x_partner
lxp_buyer: bigint (FK)
lxp_receiver: bigint(FK)
lxp_date: dateTime
lxp_quantity: int

Теперь ваша система может (используя различные типы запросов):

  1. Отслеживать, когда,где и сколько обедов каждый партнер купил / получил;

  2. Не имеет значения, кто в долгу перед теми, кто: если у партнера есть кредит, он имеет право заработать обед;

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

  4. Если все обеды имеют одинаковое значение, система подходит.Если обед будет иметь другой кредит, система подходит.Вы даже можете создать систему, используя валюту в качестве кредита (просто замените lnc_credits в таблице t002 и prt_balance в t001 на тип с плавающей запятой или на валюту).

  5. Чтобы удовлетворить ваш вызов (итого без суммы большая таблица) Я создал поле prt_balance в t001.Обновите этот баланс, когда происходит новая транзакция.Отследить переключение без дополнительной нормализации легко, если вы реализуете предложение в 3.

Не стесняйтесь комментировать, спрашивать или использовать в этой спецификации.

Я надеюсь, что я 'мы помоглиИ купи мне обед!;)

0 голосов
/ 09 марта 2011

Действительно, я тоже копаюсь, думая количественно о социальных ситуациях.

Вы бы хотели представить это тремя таблицами:

пользователей

  • id
  • name

обеды

  • id
  • местоположение
  • дата

долги

  • lunch_id (обед)
  • creditor_id (пользователь, который одолжил)
  • debtor_id (заимствованный пользователь)
  • сумма

Каждый «обед» может иметь ноль или более «долгов», связанных с ним.

Каждый «долг» имеетдва пользователя (кредитор и должник) и сумма.

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

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...