"Running balance" in mysql query? - mysql

Okay, I've searched and can't find an answer to what is probably simple, but eluding me.
I have a table of virtual currency transactions. Some of them are purchasing virtual items and some are purchasing virtual currency (via real-money transactions). I would like to monitor the in-game transactions a player makes after making a real-money transaction.
Simple schema:
userId
timestamp
transactionType (real-money or in-game)
itemId (of the in-game item they bought)
value (positive for real-money transactions that add to the user's balance, negative for in-game purchases)
newBalance (the user's new currency balance)
It's easy enough to tally the purchases made within, say 10 minutes of purchase using a self-join. What I'd like to do is give each user a balance based on the value of the currency they purchased, then tally the purchases they made using that currency until that balance runs out.
I've got to think there's an easy way to do this using user-defined variables, but it's escaping me.
Thanks in advance!

Related

Structure and logic for payouts in a marketplace application

I'm developing a marketplace-style application that allows users to upload purchasable digital items -> the public purchases these items -> and for my application to pay the users (owners of items) their owed funds via PayPal Payouts API on a daily basis.
I'm struggling with how best to calculate/store the owing balance, and how to map the individual purchase transaction records to the concept of a "payout" (when we send owed funds to the user).
Schema so far:
User
id
name
createdAt
etc.
Purchasable Item
id
user_id (owner)
price
createdAt
etc.
Transaction
id
type ("purchase" or "payout")
status (depending on PayPal response. COMPLETED, FAILED, REFUNDED etc.)
value (integer (lowest demomination of currency). Positive integer for purchase, negative for a payout).
purchasable_id (For "purchase" transactions, reference the ID of the purchasable item that was purchased)
transaction_fee
createdAt
payout_id (?) The ID of the payout (below) this purchase is included in. Not sure about this. This won't be known at the time of the transaction, so it would need to be updated to store it and I'm not sure how to know which transaction will belong in which payout?
Payout
Not sure about this. Feels like a duplicate of a payout transaction entry, but I want a way to store which purchase transactions were paid out in which payouts.
id
status (depending on PayPal response to Payout API webhook. COMPLETED, FAILED, REFUNDED etc.)
createdAt
Logic:
This is where I need the most help.
CRON job. Every 24hrs:
Calculate each users balance by summing the payout_balance_change fields of the Transactions table. i.e balance isn't stored, it's always calculated. Is that a good idea?
Insert a row into "Transactions" of type "payout" with a negative "payout_balance_change". i.e. subtracting the amount we will send in the payout, zeroing their balance in the Transactions table.
Insert a row into "Payouts" table that stores the details of the payout attempt.
Problems:
How will I know which purchase transactions belong to each payout cycle (so I can then store the payout_id in those transaction records). I could use the date of the transaction, and each payout could be for the 24hr period prior to the CRON job? I'm flexible on this and not sure what the most robust logic would be.
Any advice on how best to structure this, or links to similar projects would be greatly appreciated.
Thank you!
and welcome to Stack Overflow.
This question may be a too wide for this format - please do read "how to ask".
Firstly - I'm answering on the assumption this is MySQL. Again - please read "how to ask", tagging with multiple technologies isn't helpful.
Fistly - this on how to store money in MySQL.
Secondly - the common pattern for doing this is to have the transaction table only reflect complete transactions. That way, the current balance is always sum(transaction_value), with the transaction date showing you the balance at a given point in time. You typically store the interim state for each transaction in a dedicated table (e.g. "payout"), and only insert into the transaction table once that payout transaction is complete.
You should remove all the status and transaction_fee references from the transaction table, and store them in the dedicated tables. A transaction_fee can be represented as a transaction in its own right.
If you want to store the relationship between purchase and payout, you might have something like:
Payout
Payout_id
Payout_amount
Payout_status
Payout_date
...
Purchase
Purchase_id
Customer_id
Item_id
Purchase_date
....
Payout_purchase
Purchase_id
Payout_id
Your logic then becomes:
cron job searches all purchases that haven't been paid out (where purchase_id not in (select purchase_id from payout_purchase)
for each vendor:
create new record in payout_purchase
find sum of new payout_purchase records
attempt payout
if (payout succeeded)
insert record into transaction table with vendor ID, payout ID and payout amount
else
handle error case. This could be deleting the record (and logging the failure somewhere else), or by adding a "status" column with the value "failed". The latter option makes it easier to provide your vendors with a statement - "we attempted to pay you, but the payment failed". Either way, you want to have a way of monitoring failures, and monitor them.
end if
next vendor
I've left out the various state and error management logic steps.
Things you want to worry about:
What happens if a purchase occurs while the payout logic is running? You need to make sure you work on defined data sets in each step. For instance, you need to insert data into the "payout_purchase" table, and then work only on those records - new purchases should not be included until the next run.
What happens if a payout fails? You must ensure they are included in the next payment run.
How do you provide a statement to your buyers and sellers? What level of detail do you want?
Transaction management from MySQL may help, but you need to spend time learning the semantics and edge cases.

Update one SQL value in a table after changing a value from another table

So I have a table categories with the following columns:
Id, Category, Vat, Tax
And a products tables with the following columns:
Id, idCategory, Code, Product, Stock, buyingPrice, sellingPrice, Sales
When creating a new product the value of a product is entered and the buyingPrice is calculated by adding the Vat and Tax from the categories table to the value.
The sellingPrice is then calculated by a percentage markup of the buying price.
I now want to be able to automatically update the buyingPrice of all products if the Vat or Tax is changed.
I have tried creating a trigger but I am currently unable to work it out. I'm not sure if it's because the original value is not saved or if I am doing it all wrong. I have never created a trigger before so any push in the right direction would be appreciated.
I think Strawberry has a great comment here; you should store the VAT and tax separately and apply them to the base price that you store, rather than storing it as a final selling price that includes VAT or tax.
In your scenario, what happens if the VAT is reduced by 0.5%? Your trigger can be modified to properly account for newly inserted items, but how will you go back and correct existing ones? In the US, an item can be exempt from sales tax (if the purchaser is a certain type of non-profit organization or other exempt business, or in certain states during a sales-tax holiday). Again, in the US, sales tax calculations regarding putting an item on sale can be complicated. I'm not making the assumption that your situation will require dealing with those situations, but it seems like it would benefit you to not need to recalculate every item in your database if any of these were to apply.
If you really insist on this, I'd personally rather use a view to calculate the price on the fly rather than using a trigger to calculate it on insertion, but that's just me. Again, I'd ultimately prefer to handle this in the application logic.

Money expiration tracking

I am working with money expiration tracking problem at the moment (originally it is not money, but I have used it as a more convenient example).
An user can earn money from a platform for some mysterious reason and spent them for buying stuff (products, gifts etc.).
I am looking an algorithm (SQL query best case) to find a current balance of an user balance.
The events of spending and earning money are stored different database (MySQL) tables (let's say user_earned and user_spent). So in normal case, I would simply count user totals from user_earned and subtract spent money (total of user_spent).
BUT! There is a condition, that earned user money expires in 2 years if they are not used.
That means, if user have not used his money or used just a part of it, they will expire. If an user uses his money, they are used from the oldest not expired money record, so the balance (bonus) could be calculated in user's favor.
These are 5 scenarios with events in time, to have a better understanding on the case:
Both tables (user_earned and user_spent) have timestamps for date tracking.
I did something similar in one of my projects.
Looks like you need an additional table spends_covering with columns
spend_id, earhed_id, sum
So for each spends record you need to insert one or many rows into the spends_covering to mark 'used' money.
Then balance would be just sum of not used where date is less than 2 years.
select sum(sub.earned_sum-sub.spent_sum) as balance
from
(select e.sum as earned_sum, sum(sc.sum) as spent_sum
from earned e
left join spends_covering sc on e.earhed_id=sc.earhed_id
where e.date BETWEEN ...
group by e.earhed_id
having earned_sum > spent_sum) sub
It may be worth it to have two tables -- one (or more) with all the historical details, one with just the current balances for each 'user'. Be sure to use transactions to keep the two in sync.

Stock management database design

I'm creating an Intranet for my company, and we want to have a stock management in it. We sell and rent alarm systems, and we want to have a good overview of what product is still in our offices, what has been rented or sold, at what time, etc.
At the moment I thought about this database design :
Everytime we create a new contract, this contract is about a location or a sale of an item. So we have an Product table (which is the type of product : alarms, alarm watches, etc.), and an Item table, which is the item itself, with it unique serial number. I thought about doing this, because I'll need to have a trace of where a specific item is, if it's at a client house (rented), if it's sold, etc. Products are related to a specific supplier, to whom we can take orders. But here, I have a problem, shouldn't the order table be related to Product ?
The main concern here is the link between Stock, Item, Movement stock. I wanted to create a design where I'd be able to see when a specific Item is pulled out of our stock, and when it enters the stock with the date. That's why I thought about a Movement_stock table. The Type_Movement is either In / Out.
But I'm a bit lost here, I really don't know how to do it nicely. That's why I'm asking for a bit of help.
I have the same need, and here is how I tackled your stock movement issue (which became my issue too).
In order to modelize stock movement (+/-), I have my supplying and my order tables. Supplying act as my +stock, and my orders my -stock.
If we stop to this, we could compute our actual stock which would be transcribed into this SQL query:
SELECT
id,
name,
sup.length - ord.length AS 'stock'
FROM
product
# Computes the number of items arrived
INNER JOIN (
SELECT
productId,
SUM(quantity) AS 'length'
FROM
supplying
WHERE
arrived IS TRUE
GROUP BY
productId
) AS sup ON sup.productId = product.id
# Computes the number of order
INNER JOIN (
SELECT
productId,
SUM(quantity) AS 'length'
FROM
product_order
GROUP BY
productId
) AS ord ON ord.productId = product.id
Which would give something like:
id name stock
=========================
1 ASUS Vivobook 3
2 HP Spectre 10
3 ASUS Zenbook 0
...
While this could save you one table, you will not be able to scale with it, hence the fact that most of the modelization (imho) use an intermediate stock table, mostly for performance concerns.
One of the downside is the data duplication, because you will need to rerun the query above to update your stock (see the updatedAt column).
The good side is client performance. You will deliver faster responses through your API.
I think another downside could be if you are managing high traffic store. You could imagine creating another table that stores the fact that a stock is being recomputed, and make the user wait until the recomputation is finished (push request or long polling) in order to check if every of his/her items are still available (stock >= user demand). But that is another deal...
Anyway even if the stock recomputation query is using anonymous subqueries, it should actually be quite fast enough in most of the relatively medium stores.
Note
You see in the product_order, I duplicated the price and the vat. This is for reliability reasons: to freeze the price at the moment of the purchase, and to be able to recompute the total with a lot of decimals (without loosing cents in the way).
Hope it helps someone passing by.
Edit
In practice, I use it with Laravel, and I use a console command, which will compute my product stock in batch (I also use an optional parameter to compute only for a certain product id), so my stock is always correct (relative to the query above), and I never manually update the stock table.
This is an interesting discussion and one that also could be augmented with stock availability as of a certain date...
This means storing:
Planned Orders for the Product on a certain date
Confirmed Orders as of a certain date
Orders Delivered
Orders Returned (especially if this is a hire product)
Each one of these product movements could be from and to a location
The user queries would then include:
What is my overall stock on hand
What is due to be delivered on a certain date
What will the stock on hand be as of a date overall
What will the stock on hand be as of a date for a location
The inventory design MUST take into account the queries and use cases of the users to determine design and also breaking normalisation rules to provide adequate performance at the right time.
Lots to consider and it all depends on the software use cases.

SQL: use calculated field or leave it to the software

I'm modeling a stadium tickets database. I have a TICKET,FAN, CARD, EVENT, SEAT and SECTOR entities (and others). There are areound 40k seats, and 45 sectors. The price is calculated like this more or less:
The EVENT has a base price
The price changes depending on the SECTOR
Depending on the FAN age he could have an ulterior discount
The FAN has a CARD and depending on which type of card he could have a discount
TICKET is linked with a 1:1 to everything except CARD and SECTOR (but SEAT is weak towards SECTOR so he can see its key)
Should I calculate the price in my database? Only if I need to store it? If yes how should I do it, leave it as a calculated field in TICKET?
I hope I've been clear enough, thank for every answer
EDIT: I don't want the sql code to calculate it
I consider it a good idea to have that algorithm implemented in the database, such as to use the same algorithm and code from every app or webservice or whatever you intend to build some day.
I would create a stored procedure to calculate the price. You would call this procedure whenever you want a price calculated.
Once a ticket is issued, its price is fixed however, so you would usually store the price with the ticket. Later you may change discounts, so the same kind of ticket gets cheaper, but the one already sold doesn't of course. That said, use the stored procedure to calculate the ticket price initially. When issuing the ticket, store that current price with it.