0

I'm working on a database which stores data on members and staff for locations. Each location belongs to a location_group or company and the member data needs to hold values unique to that location_group. But the data held in the person and login tables which are used for both staff and members is not unique to and location or group. If a member was made for different location groups but was the same person then there would be a duplicated person entry. Is there a better way of doing this? This is the first complex database I have made so I probably have not made it the best way.

ERD of the tables related to this question, And this is the full ERD so far.

I am using an SQLite database with python as it is all that is available at my school. Thanks for any help.

Edit 1: The data being stored is personal information in the person table which is used by the staff and member tables so someone could be both a member and staff at a location meaning a staff could use the facilities at the location as a member. the member table hold member and location specific information such as which waivers they have signed and which facilities they can use.

  • Could you provide some examples of the data, please? – Schwern Oct 09 '20 at 19:15
  • Some sample data, not a description, would help clarify the situation. And what problems you're having with your current design? In particular, can you show what you mean by a "duplicated person entry"? If there's two entries in `person` for the same person that's bad. If member and staff both refer to the same person, that's fine so long as it's allowed for someone to be both a staff and a member. The same person might also have multiple memberships and staff positions for different locations, that's also fine. But you will want to avoid having having duplicate memberships and staff. – Schwern Oct 09 '20 at 19:42
  • The memberships and staff will be different for each location as they will all have different waivers, induction dates or staff qualifications. the problem I see is that if a person signed up as a member or staff at two different location groups then how will on the second sign up know to use the already entered data, if I want to keep that data private from the company until the person chooses to sign up with them, and not just creat another entry in the person table. – Callum Stew Oct 09 '20 at 19:52
  • "*if a person signed up as a member or staff at two different location groups then how will on the second sign up know to use the already entered data*" Because you will query a membership by the person and location_group. – Schwern Oct 09 '20 at 20:08

2 Answers2

0

Assuming that it's ok for the same person to have memberships in multiple location groups and also be on staff at multiple locations, this looks fine.

Something to be careful of is duplicate memberships. Presumably you don't want the same person to have a membership in the same location group, nor be on staff at the same location twice. You need unique indexes to enforce this.

-- Note, with this you don't need a separate index on person_id.
create unique index unique_member_idx
  on member(person_id, location_group_id);

-- And you don't need a separate index on person_id.
create unique index unique_staff_idx
  on member(person_id, location_id);

You might also want to put a unique index on person.email, being careful to normalize your email addresses (downcase them, strip leading and trailing whitespace) before inserting or as an insert/update trigger.


For the location settings, unless you're storing bit fields blob is incorrect; it's for binary data. You could store JSON as text, but SQLite lacks JSON functionality so querying it would be very slow. I'd recommend a key/value table for your location specific settings.

-- And one for location_group.
create table location_settings (
  location_id bigint not null references location(id),
  key text not null,
  value text not null
);

How you index this depends on how you're going to query it. If you plan on querying the value of a key for all locations like select location_id, value from location_settings where key = ? then put an index on key. Otherwise if you'll always query with where location_id = ?, even with and key = ? the index on location_id should be fine.

You can add a set of values by inputting the same key for the same location.

insert into location_settings (location_id, key, value)
  values (1, 'foo_list', 23), (1, 'foo_list', 42);

Or you can stick to one key and store complex values as JSON.

-- Do not allow duplicate keys.
create unique index location_settings_key_idx
  on location_settings(key, location_id);

insert into location_settings (location_id, key, value)
  values (1, 'foo_list', '[23, 42]');

A few other notes.

  • Store dates as datetime or timestamp. I know SQLite doesn't have a date type, it will ignore it and store a string, but get into the habit now. And store them as ISO 8601.
  • Declare everything not null unless it specifically needs to be null. This will save you a lot of headache later.
  • Don't limit the size of fields in the schema. You're not saving any space. Size limits are a business rule; they change and should be enforced in the app. Use text or varchar(255).
  • DO NOT store passwords in the clear. They should be salted and hashed using a library.
Schwern
  • 153,029
  • 25
  • 195
  • 336
  • Thanks that is very helpful just to clarify on the creation of new member or staff I would generate the data for the person table and query to see if there is an exact match. if so create the new member using that person id. – Callum Stew Oct 09 '20 at 21:10
  • @CallumStew You'll have to decide what an "exact match" means, I doubt you want to match every single person field. For example, you can get a person ID by email with `select id from person where email = ?` then use that to do an insert. – Schwern Oct 10 '20 at 04:19
0

Each location belongs to a location_group

That means each location belongs to 1 (or 0 or 1) location_group. If so, your tables don't show that. location should have a foreign key to location_group, not the other way around.

member data needs to hold values unique to that location_group

That means there are are data that are unique to a member at a location that is defined by the location group. For example, all VPs in the northeast group could have offices painted green on the north wall. I've seen that.

In that case, a member_location would describe a member at a location, which perforce is in a location group. Its natural key (term of art) is 2 columns: the member ID and location ID. (If you want to know what group the member's location is in, that's what joins were made for.) That assumes a member may belong to more than one location; otherwise, location is an attribute of member, and not part of the key.

If a member was made for different location groups but was the same person then there would be a duplicated person entry

I might not understand what you mean by "person entry". If a member is associated with a location (group), that is represented by a row. Additional locations require additional rows. Each row is a distinct fact. If you can remove something "duplicated" without destroying the fact, you're on the road to normalizing your database design.

Looking at your ERD, the relationships are ... unusual. For example, a member is the product of a login and a person. I can accept that a person might have more than one login, but can one login belong to more than one person? If not, then login might have a column for the person to whom the login belongs.

One note about convention, and one about design.

  • You'll find it's much more common to see foo_id or FooID or FooId than idfoo. DBMS systems rely heavily on listing information sorted alphabetically, and the users database metainformation are looking for the most important information first in the name.
  • Do not blindly assign an arbitrary integer as a primary key to each row. Look for the identifying information, and use combinations of columns to form keys. That will help you decide what is identifying information and what is not, which might be the most important aspect of database design.
James K. Lowden
  • 7,574
  • 1
  • 16
  • 31
  • Thankyou for the feedback, i am still learning database design and so do not fully understand it. A member of multiple groups should be able to use the same password the access the members site and view data about both there memberships. Also a a person could be a staff and a member that would require two logins one for the staff admin site and one for the members site so i didn't think i could link password to person. I will work on it over the weekend using you advice. – Callum Stew Oct 09 '20 at 21:22
  • Both of your comments indicate that a login has a password, and every login belongs to one person, but a person could have more than one login. We would say, if so, that the person-->login relationship is 1:M (one to many). Every login has 0:1 persons associated with it. The way to do that is to make person a non-key column of login: as you scan the login table, you may find a given person there more than once, but each login, being unique, never has more than one person. HTH. – James K. Lowden Oct 09 '20 at 21:42
  • I know this is not the correct place but here is my revised ERD https://imgur.com/a/wb4Esgm . I would appreciate feedback and if you could tell me the correct place to ask for feedback on database models. – Callum Stew Oct 10 '20 at 21:13