Database design for tracking and sharing expenses - mysql

I want to design a web application for keeping track of the finance of the members of an organization. Certain functions are very similar to Splittr. I define my requirements using the MWE database diagrams:
"Finance" tables: Each user will have one personal finance account, for which I am using the following three red tables:
"SharedExpense" tables: Each user can have shared expenses with other users in many 'shared-expense-groups'. For each group, I am using the following three blue tables:
(Note how each user can define amount of their share, and own category of the shared expense. UserShare table uses a composite primary key.)
The problem: I have to relate the users to their 3 personal "Finance" tables and the 3N "SharedExpense" tables (where N is the number of 'shared-expense-groups' the user belongs to).
Attempted Solutions:
Multiple databases. Each user has a unique database for their "Finance" tables. Each 'shared-expense-group' has a unique database on the server. I can then relate the users from one master database with the following four purple tables:
Drawbacks: Foreign keys come from different databases, large number of databases to be backed up.
Multiple tables. I can create all the tables in the same database and relate all of them with the four green master tables:
Here, the number of tables is a potential problem. If there are M users and N 'shared-expense-groups, then there will be 3M + 3N tables!
The question: Is there more elegant and simpler database design for the purpose? If not, which of the above two solutions is better and why?
Links to relevant, previous StackOverflow Q&A:
Personal finance app database design
Database design for tracking progress over time
SQL for a Household Bill splitting db
Comparing 1 Database with Many Tables to Multiple Databases with Fewer Tables in Each

There is to much to describe all the challenges in a summary, but I'll pick out a few.
Fundamental design violations: such as a table/database for each user
entity design, 3NF: such as category.budget and ledger.transaction_type
referential integrity/relationship design:
account is for one user, but account table does not contain the user id;
usershare is a subset of ledger, but they both point to a user;
object naming concerns:
clear and consistent naming entities, based on real usage. Is a member a user or a user a member? If they are the same, choose one name. If they are not the same, the design is different. Do staff use client or customer rather than member?
consistency in your key naming. The key name should directly tie it to the source entity. Members.ID should be referenced as members_id, rather than user_id. However, see the next entry before correcting this.
be consistent in your entity plurality. The general consensus is that the name should describe a single record (User) rather than all the records (Users).
ledger.spent_on - that name is not obviously a date. It could be pointing to a user or category as well. An attribute name should describe the attribute without needing additional explanation. For example, ledger.Purchase_Date is self explanatory. It should also be clear how it relates to the entity. UserShare.Share doesn't really tell me what it contains.
Sorry to be blunt, but I would start over. Consider what you have as a good trial run and start again using the additional information you have.
Ask questions of your designs (Are all users members? Are all members users?). If the answer is anything other than Yes or No, break it down further.
Try what-if scenarios (What if a shared ledger exceeds the category budget? How will previous spending be perceived if the category budget changes?)
Consider what reporting questions may be asked (Who went over budget? How much are we spending on this category?) and then consider the query to answer the question.
Read up on 3NF and maybe some of the higher normalization levels as well. Whereas 3NF is pretty nearly the minimum normalization, the higher levels become increasingly specialized and may or may not be appropriate for you design.
The better you understand your data AND business, the better your design will be, and the better your end product will turn out.

Related

ER Diagram, Physical Data Model Relations

I am trying to create a very simple database Supermarket management system.
And it seems that I am having a problem with how relations work between entities, I am using PowerDesigner to create the ERD and then generate everything from it(LDM, PDM, OOM). Is this a bad idea?.
Now for my main problem It's between these 3 tables:
Employee(Cashier)
Customer
Orders(Receipt).
The way I did it is:
The customer gather the products he wants to buy and present it to the employee, then the employee gets the order for the customer from the machine, so:
There is a relation between the Customer and the Employee (Many to Many) : each customer can request_order from one or more Employee and each Employee can get_order to one or more Customer.
There is a relation between the Employee and the Orders (1 To Many) : each Employee can get one or more orders, each order is fetched by one employee.
The problem is if I want to know the customer related to that specific order......I can't.
How do I fix this? How can I get the specific order that customer made.
I am still very new to this, so sorry for any obvious mistakes.
I am sticking to the Relational Database context, that you have tagged.
Data Modelling is an iterative process. There is a lot more definition that is needed, before the data model can be complete. Rather than answering the specifics that you request, which would be limited to one iteration; one increment, allow me to provide something more complete, several iterations progressed.
If it is useful, please discuss this data model, and progress it to fulfil all your requirements.
Of course it is too small as an inline graphic. As a PDF Supermarket Data Model.
The Standard for Relational Data Modelling since 1983 is IDEF1X. For those unfamiliar with the Standard, refer to the short IDEF1X Introduction.
I am using PowerDesigner to create the ERD and then generate everything from it (LDM, PDM, OOM). Is this a bad idea?.
PowerDesigner is great. Just ignore the Oracle-specific nonsense, it pushes you into considering the physical far too early.
Skip the ERD, it is brain-dead in the context of the Relational paradigm, and surpassed by IDEF1X, which is specific to that paradigm.
Use the Entity Level display for ERD equivalence.
For small projects you can ignore the academic distinctions {CDM; LDM; PDM; OOM, etc}.
There is actually just one model: it is "conceptual" at the beginning, and you just progress to "logical", and last, when the "logical" is stable, to the "physical".
Understand that the whole process is Logical.
Unfortunately, in PD you have to have separate "models" or files for each.
Now for my main problem It's between these 3 tables:
I have solved that issue. And exposed others.
each customer can request_order from one or more Employee and each Employee can get_order to one or more Customer
each Employee can get_order to one or more Customer
Yes, but that is the overall result. In each shopping or presentation instance:
a customer can request_order from one Employee (Cashier)
a Employee can get_order from one Customer
The problem is if I want to know the customer related to that specific order......I can't. How do I fix this?
Solved: Each Order is Identified by (CustomerId, DateTime), ie. the Customer who created the Order.
Note
Do not mix Process elements (eg. Get_Order) with Data elements (eg. the data model). The two areas are separate, and governed by quite different science. Here we are solving the Data; only the Data; and nothing but the Data. After that, the Process Model is easy.
RecordIds are anti-Relational. They are certainly not needed in a Relational database. Read my other Answers for detailed explanations.
Relational Keys (aka Compound Keys or Composite Keys) are standard fare in a Relational database. They provide far more integrity than a RecordId based file ever can.
You need to be more precise (state the exact sequence) in defining how an Order is created.
Please feel free to comment or ask specific questions.

Difference between two separate tables and one table with column

I have users and doctors. It is an app that both regular people and doctors can use. I'm not sure which way to setup my database.
Two tables - users and doctors tables
One table, extra column - users table with column user_type
Which one is the best way to do it? What are the pros and cons of both?
Keeping separate tables for me is good especially if you make user table to be as basic as possible (with username and password). This way you know that even if requirements changes in the future and you need to add another user type with other additional fields, then you don't have to worry about other sections of your code. I am just thinking about the future changes or additions. Doctors is abstract. Again this might be the problem in the future when you have to categorize them (e.g by their specialty).
Just my two cents worth.
2 tables is your best approach. Although not the 2 tables you have suggested.
If you analyze your situation a little more basically, you have users and they belong to 1 of 2 groups (general public and doctors).
This is a standard user group situation, so using 1 table to store user specific data with a reference to a user_group table (ie user belongs to group) is a good solution.
This also allows you to add groups later on - renal patient, renal doctor, cardiac patient, cardiac doctor ...
Using a setup with users and user_groups is usually a good way to go.

MySql table with potentially *very* many columns

A friend who is a recruiter for software engineers wants me to create an app for him.
He wants to be able to search candidates' CVs based on skills.
As you can imagine, there are potentially hundreds, possibly thousands of skills.
What's the best way to represent the candidate in a table? I am thinking skill_1, skill_2, skill_n, etc, but somewhere out there there is a candidate with more than n skills.
Also, it is possible that more skills will be added to the database in future.
So, what's the best way to represent a candidate's skills?
[Update] for #zohar, here's a rough first pass at teh schema. Any comments?
You need three tables (at least):
One table for candidates, that will contain all the details such as name, contact information, the cv (or a link to it) and all other relevant details.
One table for skills - that will contain the skill name, and perhaps a short description (if that's relevant)
and one table to connect candidates to skills - candidatesToSkills - that will have a 1 to many relationship with both tables - and a primary key that is the combination of the candidate id and the skill id.
This is the relational way of creating a many to many relationship.
As a bonus, you can also add a column for skill level - beginner, intermediate, skilled, expert etc'.
You might also want to add a table for job openings and another table to connect that to the skills table, so that you can easily find the most suitable candidate for the job based on the required skills. (but please note that skills is not the only match needed - other points to match are geographic location, salary expectations, etc'.)

Database design & normalization

I'm creating a messaging system for a e-learning platform and there are some design concerns that I'd like some feedback on.
First of all, it is important for me and my system to be highly modifiable in the future. As such, maintaining a fairly high normalization across my tables is important.
On to how my system will work:
All members (students or teachers) are part of a virtual classroom.
Teachers can create tasks and exercises in these classrooms and assign them to one or multiple students (member_task table not illustrated).
A student can request help for a specific task or exercise by sending a message to the teachers of the classroom.
Messages sent by students are sent to all the teachers. They cannot address a message to a specific teacher.
Messages sent by teachers can be addressed to one or more students.
Students cannot send messages to other students.
Messages behave like chat, meaning that a private conversation starts between a student and all teachers when they send a message.
Here's the ER diagram I made:
So my question is, is this table normalized properly for my purpose? Is there anything that can be done to reduce redundancy of data across my tables? And out of curiosity, is it in BCNF?
Another question: I don't intend to ever implement delete features anywhere in my system. Only "archiving" where said classroom/task/member/message/whatever is simply hidden/deactivated. So is there any reason to actually use FK?
EDIT: Also, a friend brought to my attention that the Conversations table might be redundant, and it kinda feels so. Thoughts?
Thanks.
In response to your emphasis on "modifiability" which I'm taking to mean with respect to application and schema evolution I'm actually going to suggest a fairly extreme solution. Before that some notes some aspects you've mentioned. First, foreign keys represent meaningful constraints in your data. They should always be defined and enforced. Foreign keys are not there just for cascading delete. Second, the Conversations table is arguably redundant. It would make sense if you had a notion of "session" of chat which would correspond to a Conversation. Otherwise, you just have a bunch of messages throughout time. The Conversation table could also enable a many-to-many relation between messages and tasks/exercises if you wanted to have chats that simultaneously covered multiple exercises, for example.
Now for the extreme suggestion. You could use 6NF. In particular, you might look at its incarnation in anchor modeling. The most notable difference in this approach is each attribute is modeled as a different table. 6NF supports temporal databases (supported in anchor modeling via "historized" attributes/ties). This means handling situations like a student being associated to a task now but not later won't cause all their messages to disappear. Most relevant to you, all schema modifications are non-destructive and additive, so no old code breaks when you make a change.
There are downsides. First, it's a bit weird, and in particular anchor modeling (somewhat gratuitously?) introduces a bunch of new terms. Second, it produces weird queries for most relational databases which they may not optimize well. This can sometimes be resolved with materialized views. Third, at the physical level, every attribute is effectively nullable. Finally, the tooling and support, while present, is pretty young. In particular, for MySQL, you may only be "inspired by" what's provided on the anchor modeling site.
As far as the actual database model would go, it would look roughly similar. Anchor modeling uses the term "anchor" for roughly the same thing as an entity, and "tie" for roughly the same thing as a relation. For simplicity, dropping the Conversation relation (and thus directly connecting Message to Task), the image would be similar: you'd have an anchor for Classroom, Member, Message, and Task, and a tie replacing Recipient that you might called ReceivedMessage representing the relation of "member received message message". The attributes on your entities would be attribute nodes. Making the message attribute on the Message anchor historized would allow messages to be edited if desired and support a history of revisions.
One concern I have is that I don't see a Users table which will hold all the students and teachers info (login, email, system id, role, etc) but I assume there is something similar in our system?
Now, looking into the Members table: usually students change classes every semester or so and you don't want last semesters' students to receive new messages. I would suggest the following:
Members
=============
PK member_id
FK class_id
FK user_id
--------------
join_date
leave_date
active
role
The last two fields might be redundant:
active: is an alternative solution if you want to avoid using dates. This will become false when a user stops being member of this class. Since there is not delete feature, the Members entry has to be preserved for archive purposes (and historical log).
role: Depends on how you setup Users table and roles in your system. If a user entry has role field(s) then this is not needed. However, this field allows for the same user to assume different roles in different classes. Example: a 3rd year student, who was a member of this class 2 years ago, is now working as TA/LA (teaching/lab assistant) for the same class. This depends on how the institution works... in my BSc we had the "rule": anyone with grade > 8.5/10 in Java could volunteer to do workshops to other students (using uni's labs). Finally, this field if used as a mask or a constant, allows for roles to be extended (future-proof)
As for FKs I will always suggest using them for data consistency. Things can get really ugly really fast without FKs. The limitations they impose can be worked around and they are usually needed: What is the purpose of archiving a message with sender_id if the sender has been deleted by accident? Also, note that in most systems FKs are indexed which improves the performance of queries/joins.
Hope the above helps and not confuse things :)

Improving my Database Design for future scalability

Well, I am working on a project which might involve thousands of users & I don't have much experience in databases especially when it involves relationships between entities.
Let me explain my scenario. First there's an User who can login into our system using his credentials. We have a module in our system, which will enable him to create Projects. So that brings a relationship between User table & Projects table.
Now there's another module, namely Team Creation Module, it does what it says. Out of the list of available members, he can pick who he likes and add them to a team. So there are tables for that Members & Team. Furthermore, a member can be a part of many teams and a team can have many members & a "User" can be member as well.
I have a designed the database myself but I am not sure if it is good or bad one. Moreover, I would really appreciate if someone can point me to good tutorials which shows how to insert or update into tables involving relationships.
Here's my design till now:
Update
After a discussion with someone on IRC, I came up with a revised design. I merged "User" & "Members" table as User is also a Member.
My question still remains the same, Am I on right track?
It's great that you're thinking long-term, but your solution won't work long-term.
This is not the first time this sort of thing has been tried before. Rely on the wisdom of those that have messed up before. Read data modeling pattern books.
Abstract and Normalize. That's how you get to a good long-term solution.
At least read up on The Party Model. A group and individual are actually the same (abstract) thing.
Put actually different things in different tables. An Address and Member don't belong in the same table.
"Am I on the right track" is not a useful question - we have no way of telling, because it depends on where you are headed.
A couple of things:
it's a good idea to name the relation columns after the relationship. For instance, in the first diagram, the "owner" of the project should not be called users_user_id - that's meaningless. Call it "owner_id" or something that meaningfully describes the relationship between the project and members table.
in the second diagram, you appear to have a "many to many" relationship between members and projects in the members table - but there's no efficient way of storing the id of more than one project in the members table. You need to factor that out into a joining table - projects_members, for instance, just like you did with teams_members.
the "teams_members" table has a primary key called tm_id. A purist would tell you this is wrong - the unique identifier for that table should be the combination of member_id and team_id. You don't need another unique identifier - and in fact it's harmful, because you must guarantee uniqueness of the member_id and team_id combination.
As Neil says, you probably want to start reading up on this. I can recommend 'Database Systems: Design, Implementation, and Management' by Coronel et al.