Предлагаемый вами план звучит хорошо ... Начните со следующих отношений для отслеживания людей и транзакций:
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)
Транзакции, такие как дебетовые поездки, не регистрируются.Вы можете получить стоимость по дате, присоединившись к отношению Транзакция.