About the feedback of sql diagram - sql

I actually need some feedback on the tables since my goal is to have
only the admin who can add the users and add files to the users. An admin can login and select either add users, add files for the users.Only the users who can login and download files.

Looks to me like you're missing a USER_ROLES table (primary key: UserID,RoleID). The FK from Files would be to USER_ROLES, not ROLE. Also, you should be consistent in naming tables as either singular or plural nouns. (I prefer plural).

I've made some changes on users_roles table and the only changes on the users table is only the userid in pk since I don't need the foreign key in userid.

Related

1:N relationship to profile or user table?

Suppose I have a User Table and a UserProfile Table that I have separated. The two tables have a 1:1 relationship.
User table contains only data like email and password, while UserProfile contains data like first name, last name, phone number, etc.
Does it make more sense that future tables like Projects (for projects of a user) or Ratings (ratings of a user) have a 1:N ratio to the UserProfile table or the actual Account table (User)?
Thanks for tips.
Your users table should have a unique id to identify users throughout your database. In general, this would be an integer, because those are a bit more efficient for indexes.
As for your data model, you would use this user_id for all tables that reference users. This includes userProfiles. In that table, it would be both a primary key and foreign key -- unless this were a type-2 table with version effective and end dates.
Note: I would tend to put all sensitive data in userProfiles -- including the email. An encrypted password would not need to go there. That way, you can better control access to PII ("personally identifiable information").

Best way to mimic inheritance in postgresql?

For an application I am writing, there are two types of "users", those who have made accounts and those who have not, virtual_users. These two types are nearly identical, except account_users have a password, and email is required and must be unique amongst all account_users, although it can be the same as any number for virtual_users. A large number of tables have a column that references users, which should include both, and 90% of app functionality treats them as interchangeable. What is the best way of handling this? Some options I have considered:
-Put both types of users in the same table and have a complicated constraints regarding uniqueness, basically, if password is not NULL, email must be unique among all users where password is not NULL. I have no idea how I would write this constraint. On the few occasions I only want account_users query for only users who have a password. This seems like the best solution if I can figure out how to write the constraint.
-Have Account_users inherit from Virtual_usersand Virtual_users has an additional column password and unique constraints on email. From here there are two potential options:
---Have a Users table which includes two columns account_user_id and virtual_user_id one of which is NULL and one of which corresponds to the appropriate user. When other tables need to reference a user, they reference this table. Have all my queries server side for users query both tables and combine.
---When other tables need to reference they reference either table. I don't think this is possible. Have all my queries server side for users query both tables and combine.
Any advice would be appreciated.
I assume the scenario is you have a system which some parts require the user to be signed into a registered account, and others do not, but you'd still like to track users.
Postgres has table inheritance. You could use that, but I'd be concerned about the caveats.
You could put them all into one table and use some sort of flag, like Single Table Inheritance, but then you run into constraint issues. You would then enforce constraints in the model. This should be fine if you have a strong model.
You could have separate accounts and users. Rather than one being a special case of the other, they key is thinking of them as two conceptually different things. In OO terms, an account has a user.
-- Visitors to the site who haven't signed up.
create table users (
id serial,
-- The unverified email they might have given you.
email text,
-- Any other common information like a tracking token
token text
);
-- Users who have registered.
create table accounts (
id serial,
user_id int references users(id),
-- Their verified email.
email text not null,
-- Hashed, of course.
password text not null
-- any additional information only for accounts
);
I like this because there are no flags involved, users and accounts can have separate constraints, and the accounts table doesn't get bloated with users that showed up once and never came back.
You'd access complete account information with a simple join.
select accounts.*, users.token
from accounts
join users on accounts.user_id = users.id
where accounts.id = ?
If you want to delete an account you can do so without losing the underlying user information.
delete from accounts where accounts.id = ?
Systems which require an account use accounts. Systems which don't use users. Systems which behave differently for users and accounts can check if a user has an account easily.
select accounts.id
from accounts
where accounts.user_id = ?
User tracking is associated with the users table, so you have a consistent record of a user's behavior before and after they register.

Foreign key or boolean value in database

Let's say I have a database with two tables, User and Store.
Lets make the rules:
A User must belong to one Store
A Store may have one or more Users
A store though, may have a store manager. What is the best approach for this?
Adding a 'is_store_manager' boolean column at the Users table, or create a foreign key called something like manager_user_fk at the Store table? I guess that would create a many to many relationship though, which would be bad, but it would be a solid constraint to select a user I think. What would be the best approach?
Don't create a fk on the Store. It is somewhat redundant and will make some future SQL queries harder.
You could add another table, UserType with the Manager, and Non-Manager types. You'd then add a fk on the Users table pointing to the UserType.
Edit:
If you wanted a user to be allowed multiple roles, you'd need another join table:
Let's call the previous table table Role, instead of UserType, and add another table, UserRole that is a join between User and Role (it has only 2 columns: a foreign key to User, and a foreign key to Role. With this setup, you wouldn't have any fk on the User table, as this join table would hold all the information about the relationship. A user could have as many roles as you like then.
An alternative to the accepted solution which only allows a user to be of one type you can use what I've been doing to replace boolean status fields. Create a table called UserManager with a primary key also being a foreign key to User.
Any user with an entry in UserManager is a manager. To get the managers you just join the User table with the UserManager. This also lets you store more meta data (i.e. you could store when the user became a manager etc).
Then if you want an AdminUser table, you do the same thing. Any user in the AdminUser table is also an admin. You can have a user be both (or none, or one). Along with storing more meta data about the type.

Database design relations in User and Profile

I'm designing a web application for a school. So far, I'm stuck with the database which has these tables:
users
id
username
password
profile
user_id (FK)
name
last_name
sex
group_id (FK)
(other basic information)
... And other tables irrelevant now, like events, comitees, groups and so on.
So, the users table stores basic information about the login, and the profiles table stores all the personal data about the user.
Now, the *group_id* column in the profile table has a foreign key that references the ID column of the group in which the user is currently enrolled, in the groups table. A user can only be enrolled in one group at once, so there's no need for any additional tables.
The thing is that it doesn't make much sense to me declaring a relation like group HAS MANY profiles. Instead, the relation should be group HAS MANY users, but then, I would have to put a *group_id* column on the users table, which doesn't really fit in, since the users table only stores auth information.
On the other side, I would like to list all the users enrolled in a group using an ORM and getting the a users collection and not profiles. The way I see it, is that the users table is like the 'parent' and the profiles table extends the users table.
The same problem would occur when setting attendances for events. Should I reference the profile as a foreign key in the events_attendance table? Or should I reference the user ID?
Of course both solutions could be implemented and work, but which of them is the best choice?
I have dug a little and found that both solutions would comply with 3NF, so in theory, would be correct, but I'm having a hard time designing the right way my database.
This is a question of your own conventions. You need to decide what is the main entity, right after that you can easiy find a proper solution. Both ways are good, but if you think of User as of the main entity while Profile is a property then you should put GroupId into User, otherwise, if you mean User and Profile as a single entity, you can leave GroupId in Profile, and by this you're not saying group HAS MANY profiles but group HAS MANY users.
By setting a proper one-to-one relation (User-Profile) you can force your data integrity good enough.

put login and password in one table or in multiple tables for each type of user?

I have different 3 types of users and each type of user can have columns and relationships with tables that another type doesn't, but all of them have login(Unique) and password,
how would you do:
create a table for each type or
create one table for all of them or
create a table for all of them only for login and password and separate for all the other things and bind them with a FK
something else
Number 3 is the best of the options you suggested (updated slightly for clarification):
create a table for all of them for login and password and anything else that is shared and a separate table for all the other things that are not shared and bind them with a FK
Except don't store the password, store a hashed version of a salted password.
An alternative might be to assign groups and/or roles to your users. This might be more flexible than a fixed table structure, allowing you to add new roles dynamically. But it depends on your needs whether this is useful for you or not.
As Aaronaught pointed out, in the main table you need an AccountType to ensure that a user can only have one of the roles. You must remember to check the value of this column when joining the tables to ensure that a user has only one role active.
A unique constraint on the foreign key ensures that a user can only have a role once.