6

I am struggling with a database design, this is what I have so far.

schema

Here are the problems.

  1. I need to introduce a new user type (conglomeration manager), and they will have visibility of groups of companies (a conglomeration). A conglomeration manager can have multiple companies, and a company can belong to multiple conglomeration managers. It would be advantageous if an independent company could be added, and then at a later date be easily included as part of a conglomeration.

    I am finding this difficult to model as all my users so far (manager,driver,recipient) all exist in the users table. This was by design as they all have nearly the same data fields, and I need to have a single login point for all users on my site. If I add a conglomeration manager to the users table, they will have relationships with other tables that my existing user types don't have.

  2. I am uneasy about the dependency loop formed through users, ownerships, packages, companies, users. This strikes me as bad form, but I really can't think of a way to avoid it as:

    managers, drivers and recipients all work for a single company. That company has an associated set of packages, yet I need to have the ability to associate a subset of those packages to a particular recipient (they own packages) and to a particular driver or manager (responsible for delivering those packages).

  3. I am not happy with the "receive_emails" field in users, as it is only relevant to users of type "recipient".

To add to the the problems, this design is already in use, and data will have to be migrated to any new design.

The most common operations that take place in the system are the viewing of statuses by recipients, followed by the creation of statuses by managers and drivers.

Can my problems be addressed with an elegant new design?

pingu
  • 8,719
  • 12
  • 50
  • 84
  • You're going to need to break this down into one question. This is too broad for this forum. – Mike Perrenoud Nov 29 '13 at 12:59
  • From what you said in paragraph 1, you will need a many to many relationship between users and companies. – Dan Bracuk Nov 29 '13 at 13:27
  • 1
    Don't worry about moving columns to different tables. Yes, the migration will be a bit more difficult, but you're going to live with the database design for decades. – Gilbert Le Blanc Nov 29 '13 at 15:16
  • @Dan - that would help partially, but that relationship would not make sense for some of the users. A recipient for example, only belongs to a single company. – pingu Nov 29 '13 at 18:56
  • @Gilbert - agreed, it's worth getting it right now. – pingu Nov 29 '13 at 18:57
  • @Michael - stackoverflow is a fickle place. You follow the structure of an extremely well received question. (http://stackoverflow.com/questions/2320633/first-time-database-design-am-i-overengineering) One person doesn't rate it, and then everyone follows suit. Perhaps I would have had a wealth of feedback had you not been the first person to see my question. – pingu Dec 02 '13 at 21:04
  • Hi pingu, the bounty period is ending. You should accept the answer that helps you most. – Thorsten Kettner Dec 09 '13 at 13:31

4 Answers4

2

Extend users!

Like extending a class you can create a new table "Managers" with more columns and a FK to users.

So you can create a relational table between Managers and companies.

If you want a better control over that conglomerate entity, create the Conglomerate table and make a FK to managers, so you create a relational table between Conglomerate and Companies OR if a company cannot be owned by two conglomerates just a FK from company to conglomerate.

jean
  • 4,159
  • 4
  • 31
  • 52
  • thanks for the reply! this sounds like a good idea. Any thoughts on question 2? – pingu Dec 02 '13 at 21:00
  • Same answer: Extend users! You can create recipients and drivers table extending the users table. Don't get uneased by a possible loop, since that users are not the same it ill not happen. – jean Dec 03 '13 at 11:21
  • Well if a driver can get promoted to manager or a manager can get a delivery for himself it actually can loop but I don't see that as a issue. Anyway you already made the hardest work, create the concepts. If the scenario is god (is coherent with the reality and business logic) just adhere you data design to it and you ill be fine. – jean Dec 03 '13 at 11:37
2

I need to introduce a new user type

In these type of scenario when adding a new type is required, that would result in restructuring of schema, leads me to a defect in design.

Actually managing and driving are roles played by a user that may change over time.
In reality:
A user is-not-a manager (he is a person).
Managing is-a-role-played-by a user.
Think about if the company decides to have help-desk users.

I will add Role and User-Role tables to keep the relation between user and role.

I am not happy with the "receive_emails" field in users.

Having receive-email field in User-Role will be an option.

I need to have a single login point for all users on my site

May having user, company and role as selections on log-in page helps (that will have direct impacts on your application design).

I am uneasy about the dependency loop formed through users, ownerships, packages, companies, users.

Conceptually we will have recipient-user => ownership => package => company => driver or manager user.
BTW its a relational model.

Conglomerations.

enter image description here

Mohsen Heydari
  • 7,256
  • 4
  • 31
  • 46
1

3: Don't worry too much about the receive_emails field. Keep in mind that your database is just a model of the real world and doesn't have to be perfect. Yes, you could make "recipients" a table of its own. Consider what you would gain and what you would lose. As it is, it is no bad design. You may use a trigger to set receive_emails to false in case the user is not a recipient. Or use a view in order to hide the field for apps dealing with drivers or managers. Just as you like. Well, if you really want to get rid of the field, you could have a table "emeil_recipients" holding all user ids who are recipients of e-mails. You see there are many ways to address this, and they all have their own advantages and disadvantages. Your design as it is is fine.

2: As far as I understand it, every package has up to one manager, one driver and one recipient. Is that so? Then why have a table "ownerships" at all? Put three fields in your "packages" table; user_id_driver, user_id_manager, user_id_recipient. So your model is much closer to reality. (you can create a view "ownerships" to replace the table "ownerships" during migration time.)

1: Now to the conglomerations. Easiest would be to introduce two new tables: First you would have a table "company_groups" with an id and maybe a description field. Your table "users" would have a field "company_group_id" which would replace the field "company_id". Thus you link users to company groups rather than to single companies. Your second new table would be "company_group_members" with just two fields, id_company_group and id_company. You would build "groups" consisting only of one single company (for the managers, recipients and drivers) and groups consisting of more companies (conglomerations for the conglomerations managers). So your database doesn't change that much, but offers all you need.

Having said all that, you could still think about reducing your table "users" to the common fields and have new tables "managers", "recipients", "drivers" and "conglomeration_managers" holding additional fields. This gets you closer to reality and makes the link to packages clearer. However, it comes at the cost of a more different model from your current one. And what if you add co-drivers, secretaries or whatever later? Every time a new table for a new job? Again: There are many ways to build your model. Choose the one that suits you best.

I hope my advice helps you think it all through.

Thorsten Kettner
  • 89,309
  • 7
  • 49
  • 73
  • WThorsten - thanks for the reply. "As far as I understand it, every package has up to one manager, one driver and one recipient" - no, a package could be associated with multiples of those users. – pingu Dec 06 '13 at 16:37
  • Okay, I am going to think about it again. So in your system there are users that can login. These are managers of a company, drivers working for a company, recipients not belonging to a company, but getting something from one and only one company? And then there are conglomeration managers, each managing one or more companies. There are no other users than these. Right so far? – Thorsten Kettner Dec 06 '13 at 21:11
  • Having thought it all over again, I've decided to write a new answer rather change the existing one. Although you could still combine them, I think my new answer solves all your problems well, and you can forget about my first answer :-) – Thorsten Kettner Dec 07 '13 at 22:49
1

Well here is another try. I still think

  • you shouldn't worry too much about that receive_emails field, as explained in my other answer.
  • you don't have to split users into user kinds.

What you are worried about in 2 is the dependencies. Dependencies are usually not a problem, but you are very strict in your id based database design, thus hiding the dependencies from your dbms. If it just knew, it could help you :-)

You could do this:

  • Stick to your table "users", but remove the company_id.
  • You don't have to make any changes to "companies", "packages", "participations" and "statuses".
  • Add a table to link users to companies. Let's call the table "affiliations" for the moment. (I don't know if this would be an appropriate name, my English fails me here.) Like ownerships this is just a link table, so the only fields are user_id and company_id (forming the primary key).
  • Now add company_id to "ownerships". (I know, it is kind of there implicitly because of your link to "packages", but the dbms doesn't know that.) So add the field and now that your dbms sees the field, you can also add a constraint (foreign key) on package_id plus company_id to "packages" and a constraint on user_id plus company_id to "affilations".

That's it. You haven't changed much, but now a user can be affiliated to many companies (conglomeration managers so far, but maybe you decide one day to allow recipients to work with multiple companies or let drivers work for more than one of the companies at a time). And there is no risk of wrong entries now in "ownerships" or any doubt aboout ist content and use.

If you want to play safe with your receive_emails field, here is a way you might want to go (as I said, it is not really necessary): Have a new table email_recipients with two fields: user_id and user_type. Yes, redundancy again. But doing this, you can have a constraint on user_type only allowing certain types (only "recipient" so far). Again you would have a foreign key not only to user_id, but to user_id plus user_type.

Thorsten Kettner
  • 89,309
  • 7
  • 49
  • 73