SQL circular foreign key - sql

Assume a database holds some accounts and its transactions.
There would be a table Account (for simplicity it holds only an id) and a table Transaction that has columns id, account_id (foreign key), type, and value.
Now, if some money gets deposited there is no problem. account_id is chosen and type and value are defined. But what if I want to transfer money from account a to account b?
I thought about adding some kind of offset_account_id to distinguish from where to where but this is not a good solution imo.
Or do I add two transactions for each of the involved accounts? Then I first have to insert both and after update both as they need to have a circular reference to each other.
Third I thought about adding a 'transfer' table that will hold the transaction_id of the involved accounts.
My problem with the last solution nonetheless is if I delete account a I want to cascade this throughout the database, all transactions should be deleted automatically. But if I delete a then the transaction for a will disappear and the entry in the transfer table as well but the transaction of account b would still be in the database.
What is a good layout for these 'accounting' problems?
Side question: would you calculate balance at runtime or work with on insert/delete/update triggers to store the balance with the corresponding account?

I am posting an example of the tables described above. In this example, the account ID "100" has made a payment of $30 to the account ID of "123". The transaction shows up as a record in the payable table and as a record in the receivable table.
Then if the account for 100 is closed one day, you would remove the remaining balance from the account by creating a new record in the accounts payable table. If the money is transferred to a new account then a record would also be created in the accounts receivable table. This will show the history of funds moving. If you are wanting to keep track of which accounts are open or closed I would also suggest creating a table that contains all account numbers, customer names, and a column for "open/closed". That way closed accounts will be reflected in your data and you can still query based on open or closed accounts, but the history will not be deleted, which is vital for good accounting records.

Related

SSIS Error on insertion - Error when new primary keys in Dimension table

I am using SSIS to bring in a bunch of large files each month into one single table, which I insert records to SQL Server tables. My fact table is actual financial transactions that occur during the month. It looks something like:
FactTransactions
'Acct Number' 'Product Number' 'Total Value'
000001 1A 1000
000002 1A 2000
000001 3B 3000
I'd like to track this information against some manually generated information in a table about accounts where 'Acct Number' is the primary key in the Dim Table
DimAcct
'Acct Number' 'Acct Name' 'Acct Type'
000001 Sales Revenue
000002 Returns Revenue (Contra)
My process is:
1) Clear the transaction table
2) Reload all the transactions included anything new or corrected
3) Do Analysis through Joins, etc
When I went to run the tables in a new month, I received the following error in SSIS:
"The INSERT statement conflicted with the FOREIGN KEY constraint
"FK_GLTransaction_List_Master_DimAccount". The conflict occurred in
database "GLTransactions", table "dbo.DimAccount", column 'Acct_Number'.".
I am guessing this is because new accts have been made and used in Transactions, but I haven't manually updated my Dim file and had no warning about them. This is going to happen every month, because new Transactions accounts get added when they find new Accounting items to track separately in their own accounts. I also manually update the table to add the few accounts. Is there a way to avoid this, or better, what should I do before/during the SSIS run to handle these new accounts and avoid the error?
The message you receive tells you that in the data you are trying to load in the fact table, there is at least one record referencing a record that doesn't exists in the dimension table.
How do you load the dimension table? Do you load it only before running the fact load ? If this is the case you should consider to manage the so called "inferred dimension", that is dimension that you do not know before loading the fact table. This situation is also referred to as "early arriving facts".
Therefore, you should scan the facts you are trying to load, looking for dimension records that are not in your dimension table. Then you will insert this records in the dimension table and flag it as inferred. At this stage you will load the fact.
Note that flagging these record as "Inferred" will enable you to refine the dimension record at a later time.
Let's say you will insert an inferred account for which you know only the account number (the business key) but not the others information such as account description etc ... You can update these information at a later time.
Notice that in SSIS SCD component you can define a proper Inferred Dimension management.
Hope this helps.
You mention that you are only manually inserting dimension tables, that needs to be changed.
You should insert all new accounts as "New/Unknown" in the account dimension as a 1st step of the SSIS process.
Then you will have a report that prints these new accounts and you will manually or in some other way update these accounts to contain correct data.
You can read more about possible solutions at: https://www.matillion.com/blog/late-arriving-dimension/

How to Store Different Types of "Products" in a database

I am developing a database and not how to best store this information in my sql db.
A user can buy a subscription(ie months of access) and buy credits to do certain actions on my site(each action decreases the credits down).
Do I need to make separate tables to store this as, for instance subscription may give them 3 months access but credits would be just a value with a number that would decrease or increase if they buy more.
From what you have provided until now, I would do the following:
table [customer], fields: customer_id,....
table [subscription], fields: subscription_id,customer_id,start_date,expiration_date,initial_credits
table [action], fields: date,subscription_id,credit_cost,action_type,....
Maybe add a redundunt field of current credits to subscription table if you need it fast.

Database Schema Design: Tracking User Balance with concurrency

In an app that I am developing, we have users who will make deposits into the app and that becomes their balance.
They can use the balance to perform certain actions and also withdraw the balance. What is the schema design that ensures that the user can never withdraw / or perform more than he has, even in concurrency.
For example:
CREATE TABLE user_transaction (
transaction_id SERIAL NOT NULL PRIMARY KEY,
change_value BIGINT NOT NULL,
user_id INT NOT NULL REFERENCES user
)
The above schema can keep track of balance, (select sum() from user_transction); However, this does not hold in concurrency. Because the user can post 2 request simultaneously, and two records could be inserted in 2 simultaneous database connections.
I can't do in-app locking either (to ensure only one transcation gets written at a time), because I run multiple web servers.
Is there a database schema design that can ensure correctness?
P.S. Off the top of my head, I can imagine leveraging the uniqueness constraint in SQL. By having later transaction reference earlier transactions, and since each earlier transaction can only be referenced once, that ensures correctness at the database level.
Relying on calculating an account balance every time you go to insert a new transaction is not a very good design - for one thing, as time goes by it will take longer and longer, as more and more rows appear in the transaction table.
A better idea is to store the current balance in another table - either a new table, or in the existing users table that you are already using as a foreign key reference.
It could look like this:
CREATE TABLE users (
user_id INT PRIMARY KEY,
balance BIGINT NOT NULL DEFAULT 0 CHECK(balance>=0)
);
Then, whenever you add a transaction, you update the balance like this:
UPDATE user SET balance=balance+$1 WHERE user_id=$2;
You must do this inside a transaction, in which you also insert the transaction record.
Concurrency issues are taken care of automatically: if you attempt to update the same record twice from two different transactions, then the second one will be blocked until the first one commits or rolls back. The default transaction isolation level of 'Read Committed' ensures this - see the manual section on concurrency.
You can issue the whole sequence from your application, or if you prefer you can add a trigger to the user_transaction table such that whenever a record is inserted into the user_transaction table, the balance is updated automatically.
That way, the CHECK clause ensures that no transactions can be entered into the database that would cause the balance to go below 0.

Optimal DB structure for a membership website with free and paid subscriptions

There is a regular Users (UserID, UserName, Email, Password) table which handles user registrations.
Which other tables should be added in order to handle paid membership with 2 types of paid subscriptions - Monthly and Yearly.
I think you may want to distinguish between membership details and transactions. I like the idea of adding a membership_type column (should be a tinyint column with a separate lookup table), then having a membership_expiration column as well. If you want to track each membership purchase, you can have a separate transaction table that tracks purchases. This also gives you the ability to expand to other types of purchases or transactions in the future without modifying the data model.
How about adding a membership field to the users table with one of three values- null, monthly, or yearly?

Should I denormalize Loans, Purchases and Sales tables into one table?

Based on the information I have provided below, can you give me your opinion on whether its a good idea to denormalize separate tables into one table which holds different types of contracts?.. What are the pro's/con's?.. Has anyone attempted this before?.. Banking systems use a CIF (Customer Information File) [master] where customers may have different types of accounts, CD's, mortgages, etc. and use transaction codes[types] but do they store them in one table?
I have separate tables for Loans, Purchases & Sales transactions. Rows from each of these tables are joined to their corresponding customer in the following manner:
customer.pk_id SERIAL = loan.fk_id INTEGER;
= purchase.fk_id INTEGER;
= sale.fk_id INTEGER;
Since there are so many common properties among these tables, which revolves around the same merchandise being: pawned, bought and sold, I experimented by consolidating them into one table called "Contracts" and added the following column:
Contracts.Type char(1) {L=Loan, P=Purchase, S=Sale}
Scenario:
A customer initially pawns merchandise, makes a couple of interest payments, then decides he wants to sell the merchandise to the pawnshop, who then places merchandise in Inventory and eventually sells it to another customer.
I designed a generic table where for example:
Contracts.Capital DECIMAL(7,2)
in a loan contract it holds the pawn principal amount, in a purchase holds the purchase price, in a sale holds sale price.
Is this design a good idea or should I keep them separate?
Your table second design is better, and, is "normalised".
You first design was the denormalised one!
You are basiclly following a database design/modelling pattern known as "subtype/supertype"
for dealing with things like transactions where there is a lot of common data and some data specific to each tranasaction type.
There are two accepted ways to model this. If the the variable data is minimal you hold everthing in a single table with the transaction type specfic attributes held in "nullable" columns. (Which is essentially your case and you have done the correct thing!).
The other case is where the "uncommon" data varies wildly depending on transaction type in which case you have a table which holds all the "common" attributes, and a table for each type which holds the "uncommon" attributes for that "type".
However while "LOAN", "PURCHASE" and "SALE" are valid as transactions. I think Inventory is a different entity and should have a table on its own. Essentially "LOAN" wll add to inventory transaction, "PURCHASE" wll change of inventory status to Saleable and "SALE" wll remove the item from inventory (or change status to sold). Once an item is added to inventory only its status should change (its still a widget, violin or whatever).
I would argue that it's not denormalized. I see no repeating groups; all attributes depending on a unique primary key. Sounds like a good design to me.
Is there a question here? Are you just looking for confirmation that it's acceptable?
Hypothetically, what would you do if the overwhelming consensus was that you should revert back to separate tables for each type? Would you ignore the evidence from your own experience (better performance, simpler programming) and follow the advice of Stackoverflow.com?