How would I normalize this un-normalized database table? - mysql

I am programming a site which stores poker session data. A session is a period of time spent at a casino playing poker. A session contains information such as the date/time, the net profit/loss of the session, and the location where they played. However, the part I'm confused about is how to handle a session type. In poker there are two kinds of games: cash games and tournaments. Each have their own specific fields pertinent only to them. Here is an example table (I've removed the irrelevant fields):
+----+--------------+--------+--------+
| id | session type | stakes | buy-in |
+----+--------------+--------+--------+
| 1 | cash | 1/3 NL | NULL |
| 2 | cash | 1/2 NL | NULL |
| 3 | tournament | NULL | $20 |
+----+--------------+--------+--------+
As you can see, I do not need buy-in if the session type is cash. Similarly, if the session type is tournament, I do not need the stakes field.
How would I go about normalizing my table such that I do not have NULL fields? Performance-wise, will my application suffer if I'm normalizing this table just to make it so I do not have NULL values in my row?

Here is one possible solution:
sessions:
id_session (PK)
session_type (Integer/Enum)
cash_sessions:
id_session (FK)
stakes
tournament_sessions:
id_session (FK)
buy_in
So, separate table for every session type, thus you will be able to define different columns for different types, also have common columns in sessions table
Example data:
sessions
1 1
2 1
3 2
cash_sessions
1 1/3 NL
2 1/2 NL
tournament_sessions
3 $20
Another solution:
sessions:
id_session (PK)
session_type (Integer/Enum) <- basically useless field for this schema
attributes:
id_attr (PK)
name (String)
session_attributes:
id_session (FK)
id_attr(FK)
value (String)
so, instead of thinking in terms of "session type" you can change your business model to think about "session attributes", so, different sessions can have different sets of attributes assigned
Example data:
sessions
1 1
2 1
3 2
attributes
1 stakes
2 buy_in
session_attributes
1 1 1/3 NL
2 1 1/2 NL
3 2 $20

Related

Housing Society management system database structure

I am designing billing structure for housing society yesterday I googled and gone through banking billing structure and designed my database structure but I am not sure whether this would be correct. So I am putting my billing database structure.
Please tell me if I am wrong any where or any changes has to be done in my database structure.
And one more questions where I have to post society balance (debit, credit )like eg expense Bldg insurance and income like Adv board hoarding and also not sure about balance audit trail (having it in transaction table of separate table with transaction id as FK).
Please note all table will have by default have created,modified time, by and ip address
Table billingstatement
id | description | amount | Bill Month | userId | societyId
1 | Maint Chrg 1000 sqft x 5 per sqft | 5000 | Aug-16 | 1001 | 101
2 | Water Charges | 200 | Aug-16 | 1001 | 101
3 | Construction Charges | 300 | Aug-16 | 1001 | 101
4 | Reserved Parking chrgs | 500 | Aug-16 | 1001 | 101
Table Accounts
id | balance(current bal) | societyId | modifiedTime |
1 | -6000 | 101 | 2016-01-01 21:01:01 |
2 | -5000 | 101 | 2016-01-01 21:01:01 |
3 | 1000 | 101 | 2016-01-01 21:01:01 |
Table transaction
id | amount | balance | trans_type | trans_time | account_id |
1 | 6000 | 0 | 1 | 2016-01-01 21:01:01 | 1 |
2 | 5500 | -6000 | 1 | 2016-02-01 21:01:01 | 2 |
tran_type :- 1 = Payment by user, 2 = Income to society, 3 = Expense to society
Table map_account_user
map_id | account_id | user_id
1 | 2 | 1001
If account mapping is not present then it means it is a society account and not a user account.
Reference :-
billing banking desing
banking project sample
I have a hesitation with storing an aggregate with the entity. Unless the aggregate is very difficult to calculate, you should always account for these by examining the details.
I'm assuming you are designing a relational database. In a relational database, you normalize the data.
I'm having trouble following your database design because you have too many different fields called id. Each id field should get a unique name, so people can tell what the different id fields represent.
Let's start with the Transaction table. Generally table names are singular. I capitalize table names and column names. You don't have to follow that convention.
Transaction
-----------
Transaction ID
Transaction Type
User ID
Society Account
Transaction Amount
Transaction Time Stamp
...
Transaction ID is an auto-incrementing integer. It is also the primary (clustering) key to the Transaction table. Transaction Type is 1 = Payment by user, 2 = Income to society, 3 = Expense to society. I'm not sure what the difference is between Transaction Type 1 and Transaction Type 2.
Either the User ID or the Society Account column is filled in. The User ID column is filled in for Transaction Type 1 and the Society Account column is filled in for Transaction Types 2 and 3. The not filled in column is set to null.
Transaction Amount is always a positive value. Your code will subtract the Transaction Amount from the Society Account for Transaction Type 3.
You will create a unique index for (User ID, Transaction Time Stamp descending, Transaction ID) and a unique index for (Society Account, Transaction Time Stamp descending, Transaction ID). This allows you to quickly get all the transactions for a user or society account, for a given month.
Next, let's look at the UserAccountBalance table.
UserAccountBalance
------------------
User ID
Balance Year and Month
Balance Amount
...
The primary key to this table is (User ID, Balance Year and Month descending). You maintain the historical balances for each month for each User ID. This allows an auditor to verify the balances by running queries against the Transaction table.
Next, let's look at the SocietyAccountBalance table.
SocietyAccountBalance
---------------------
Society Account
Balance Year and Month
Balance Amount
...
This table is similar to the UserAccountBalance table, but for Society accounts.
Next, let's look at the Billing table
Billing
-------
User ID
Billing Year and Month
Billing Type
Square Feet
Charge per Square Foot
Total Charge
...
The primary key is (User ID, Billing Year and Month descending, Billing Type). I'm assuming that you only get one billing charge per billing type per month.
Billing Type is 1 = Maintenance Charge, 2 = Water Charge, 3 = Construction Charge, 4 = Reserved Parking Charge. You can generate the text on the bill from the values in this table, so there's no need to store the text in the database. The Square Feet and Charge per Square Foot columns are filled in for Billing Type 1, otherwise they are null.
You still have to match up the payments with the billings, but this should be enough to get you started on the right path.
The structure works. I would change the id naming a bit.
account_id is referenced in some places
but in the account table it is Id.
I would make it account_id in the Account table. This makes it easier to locate where you can join for the users of the database. Every place you call it "Account_Id" is should be the same Account_Id with a single master table that generates it.
Really appreciated for your efforts. You reference on banking system is really a best approach. I would like to provide you some ideas which may help you if you feel it is better for you.
Let's start. If you use your description column's data:
{Water Charges
Construction Charges
Reserved Parking chrgs}
as a new columns, your no of rows will be decreased and since you can have efficient data maintenance. For each userId you can have a single row of data rather than maintaining four rows. Just verify below provided example.
For each sq ft you can have a description column separately.
id | userId | societyId | BillMonth | MaintChrg | WaterCharges | ConstructionCharges | ReservedParkingCharges | Description
1 | 1001 | 101 | Aug-16 | 5000 | 200 | 300 | 500 | Maint Chrg 1000 sqft x 5 per sqft
2 | 1002 | 101 | Aug-16 | 4000 | 200 | 300 | 500 | Maint Chrg 900 sqft x 5 per sqft
3 | 1003 | 102 | Aug-16 | 5000 | 200 | 300 | 500 | Maint Chrg 900 sqft x 5 per sqft
For you doubt on debit and credit use:
debit as expenseBldginsurance
credit as Adv board hoarding
You can also add may other columns like user name, No of peoples, electricity charges, etc.

Difficulty in database design

I am experiencing difficulty in MySQL database design.
I have the following tables:
school_table
id | school_name
---------------------------
1 | success primary school
stage_table
id | stage_name
---------------------------
1 | nursery
2 | primary
3 | secondary
school_stage_table
id | school_id | stage_id
---------------------------
1 | 1 | 1
2 | 1 | 2
school_stage_table is a linking table. This is because there is many to many relationship between school and stage, that is a single school may have many stages, and the same stage may have many schools.
The problem comes here:
Each stage has different attributes, and therefore different attribute values for different schools.
How do I model this scenario in a database? Need your help.
As you previously said that you are having some issues that how to store different attributes of each stage of each schools.
Here you can take one table which will store all the attributes of each stage. You can use following table for storing attributes.
Table :
school_stage_attributes_table
id | school_stage_id | attributes_name | attributes_value
------------------------------------------------------------
1 | 1 | attrib_1 | value_1
2 | 1 | attrib_2 | value_2
One option here would be to create a stage_attribute table containing at least the following four columns:
stage_attribute
id | school_id | stage_id | attribute
Each record in this table would correspond to a single attribute for a single stage, e.g.
1 | 1 | 1 | 'nap time'
2 | 1 | 1 | 'breakfast'
3 | 1 | 3 | 'phys ed'
I suspect that some of the difficulty in your mind was with the possibility of adding attribute columns to the stage_table for each attribute. Of course, this is problematical because each stage could have different numbers or types of attributes, and it won't scale for many attributes. The option I gave above eliminates many of these problems by using an arbitrary number of records to store the stage attribute information.
You should use table school_stage_table for this different attribute values for different schools.
If You will use the same attributes schema for multiple schools, then there should be one more table called for example school_stage_options with fields
school_stage_options_id | stage_id | option1 | option2 ....
and later use school_stage_options_id in school_stage_table instead of using stage_id.

One to many table with 3M records

I have a table in MySQL that contains almsot 3 million records.
The table saves friend information in a user system. So it has many users and even more friends (There is a (soft)max of 2000 per user). I had added some extra fields name, url, dob, image, registered which are varchar(255) and dates.
My basic data is 2 int's and 1 varchar(6).
When using PHPMyAdmin it all gets really slow. I have an index on the user ID and the varchar(6) and that's how I query all the friends of a user (which goes well). However, any other operation (or the ones to come) aren't going to be fast.
My options:
Remove the double data (Normalizing)
Change the datatype for the friend IDs and save it like a JSON blob
So questions;
When my table is only 2 ints and a tiny varchar, will it still be
slow with 3M records?
Should I change my datatype?
Should I be
using a different pattern for this friendlist problem?
Edit: To clarify a bit more.
The Users are not my actual users, but they are user objects nonetheless. All the Friends are a User object, but I may or may not already have the User object. So I'm using the extra data in Friends to show data about it in the list on the Users page.
In the ideal world things wouldn't take so long, in the next optimal world I would only have 2 fields in Friends which are user_id and friend_id. But I can not rely on linking friend_id to a User object, I may not have it..
Users (has more fields, but for brevity)
+-------+---------+-------+------------+
| shard | user_id | name | dob |
+-------+---------+-------+------------+
| nl | 1 | Bob | 2014-03-26 |
| nl | 2 | Erik | 2014-03-26 |
| de | 1 | Johan | 2014-02-01 |
+-------+---------+-------+------------+
Friends (has more fields, see description above)
+-------+---------+-----------+--------+
| shard | user_id | friend_id | name |
+-------+---------+-----------+--------+
| nl | 1 | 2 | Erik |
| nl | 1 | 3 | Alice |
| de | 1 | 2 | Rasmus |
+-------+---------+-----------+--------+
nl-Bob is friends with nl-Erik (Is a user)
nl-Bob is friends with nl-Alice (Is not a user)
de-Johan is friends with de-Rasmus (Is not a user)

combine data - keep unique key

I have several large tables (~100 million rows in total) which all have a similar schema: They log certain settings of an object (u_id) at a point of time
u_id | x | y | time
---------------------------
1 | 2 | 3 | [timestamp]
1 | 1 | 3 | [timestamp]
2 | 1 | 2 | [timestamp]
2 | 2 | 5 | [timestamp]
3 | 3 | 2 | [timestamp]
I now want to combine these tables into one large table which is holding ALL data. However I want to leave the u_ids unique. Obviously each source table does have e.g. u_id 1. When combining the data in the result table the entries should still be distinguishable (however I do not need to associate them back to their original values). This only has to be done once so performance does not matter.
My first idea was to add a prefix (like a_, b_, etc.) to each u_id before writing it to the destination but this obviously would introduce overhead. I'd prefer that the destination table would use an AI value for minimum overhead but I don't know how to achieve that as each source u_id can have multiple (several thousand) entries.
I think you should take one column for Type in your destination table . Type will be represent different tables of source . then you can combine u_id and Type as primary key . it will solve your problem .

Set up Table to store variable number of fields per record?

How should I set up my database / table, if I do not know the number of fields I would populate per record?
For example, if I have a web form that allows a user to enter all the cars he owns, and I don't want to limit him to a certain number, how would I store this in the database end?
The above problem extends to similar situations such as storing a user's order (variable number of items per order) etc.
In Relational Database Management Systems (RDBMS) instead you create child records in a dependent table that relate child entities (cars) with parent entities (users). There is a concept known as database normalization, and the objective is that each table contains data for a single type of entity.
So you have a user table with the user information:
user_id | user_name | email | ...
1234 | User1 | user1#example.com | ...
2356 | User2 | user2#example.com | ...
Then another table for storing the information of each car of a user:
user_car_id | user_id | car_label | make | model | ...
1 | 1234 | MyCar | Ford | 2011 | ...
2 | 2356 | A Car | Chevrolet | 2010 | ...
3 | 1234 | MyOtherCar| BMW | 2000 | ...
So instead of storing the info of the cars in the user table, you have a table for storing car (user_car) information related to each user by way of the user_id column. This is an example of a one-to-many relationship, in which one user can have many related cars.
this is an entire topic: database normalization.
the short answer is you make more than one table.
in your example you would have person table, a car table, and a third that linked person to the car