Null foreign Key or table join - mysql

I have a user profile table.
id int (pk)
user_name varchar(50)
email_address varchar(100)
relationship_status tinyint(1)(FK)
I then have a relationship table. Relationship is optional field in user profile table. Is it best practice to do a null join if relationship_status is not selected or a table between relationship and user_profile.
This is simple example but I would ultimately end up with multiple tables in between if a join was optional. This might make for too many joins. However I have read can run into issues with null joins and not best practice.

It depends on the relationship between the tables. If it's a one-to-many or a many-to-many. If each user can have one and only one relationship status then do "null join" if each user can have multiple relationships than do a "table in between"
Example of a one-to-many relationship:
User Table
- id
- name
- relationship_id
Relationship Table
- id
- type
In this instance Relationship Table would have data like "user", "admin", etc and a user can only be a "user" OR an "admin" but not both. (In this particular case sometimes I will have the Relationship table's id column would be a string like "user" or "admin" that way you don't have to do a join on it, you always have it in the user table).
Example of a many-to-many relationship:
User Table
- id
- name
Relationship Table
- id
- type
User Relationship Table
- user_id
- relationship_id
In this case a user can have multiple relationships. The relationship table would have data like "editor", "reviewer", "copywriter", "admin", etc. and each user can be any combination of those (i.e., user 1 can be an editor AND a copywriter).

Related

Mysql table relation for a user with multiple business

How to properly implement mysql table relation such that a user can create multiple business and each of those business can have multiple users. thanks
Basically going to be two (possibly 3 tables):
Business Table:
business_id int (this will be the primary key)
business_name
whatever extra fields that relate to the business
User Table:
user_id whatever type (this will be the primary key)
user_name
whatever extra fields that relate to the business
The relational part you can implement in one of two ways:
add the business id to the user table. So user table will have an additional field business_id and will relate back to one of the rows in the business table. This implies a user can only relate to 1 business.
If you want a user to be able to relate to one or more businesses then you need a separate table:
Business_User Table:
business_id int
user_id (whatever type you picked)

Trying to implement friendship between users. What kind of relationship do I need between the User model and the Friend model

Currently I have a Users table and a User model. The Users table looks like this:
Table: Users
Columns: id, username, password, email
I assume if I want to implement friendship between users, I'd need to create a Friend model and Friends table which would contain the ids of the 2 users that have become friends
Table: Friends
Columns: id, userId, userId
Where both userId would be a foreign keys from the Users table. I'm using Sequelize ORM but I'm not sure what the relationship between the User and Friend models should be. I'm thinking many-to-many relationship but I'm a bit confused how to do it since both foreign keys are from the same table, therefore I need only 2 tables instead of 3.

Get a list in MySQL

I'm creating a website and users can add friends. I want them to be able to see their personal friends on a page.
For exemple:
John add user Tim and Bill.
When John goes on his friends list page, I want him to be able to see that he has Tim and Bill. How do I do that? Is that even possible? Do I need more than one table? If so, does every user has to have his own friendsList table?
Yes this is possible, you do this by querying the information from the database, the answer for if you need multiple tables etc all depends on your current table structure but at the very least you need to have some way of referencing that a Person 'John' has friends, wether thats just a 'friendID' in the same 'Person' table, or another means of doing so. then it is just a matter of querying the data correctly to return what you want and bind to the websites fields :D
One way of defining the structure is the following:
Person
PersonId
Name
<other person fields>
Relationship
RelationshipId
Name --> allow to define multiple relation types like Friendship, Follows etc.
Relationship
RelationshipId
Person1Id --> FK to Person
Person2Id --> FK to Person
RelationshipTypeId --> FK Relationship
Basically, you use an n:n between Persons (anyone can have any number of friends) and also allow for other types of relationships.
Assuming you already have a table of users, one approach would be to create a "friends" table which relates users to other users.
CREATE TABLE friends (
`user_id` INT NOT NULL,
`friend_id` INT NOT NULL
);
Both user_id and friend_id would have foreign key constraints on your existing users table (so that you guarantee an id must exist in your user table in order for it to exist in the friends table as either a user_id or friend_id).
You can then link your user table on users.id = friends.friend_id to get the friend's info.
Here is a SQL Fiddle Demo showing how this works.
You should consider using an ON DELETE CASCADE constraint on the friends table, so that if a user is deleted from the user table, the associated records in the friends table are also deleted.

database schema for two similar users

I have a doubt about this DB schema I'm making.
I have two similar users, but one has extra information than the other:
Type 1 : Administrator
- Name
- Lastname
- Email
- Password
Type 2: Student
- Name
- Lastname
- Email
- Password
- Status
- Sex
- Among other type of personal information fields
So, I'm hesitating about either make these two separate tables, and when they're going to log in, query them both (Because I have only one logging screen), or unify them as only one table User, and make another called like "extra" with a foreign key from User pointed to the latter.
What would be the most efficent way to accomplish this? Thanks for your time
I would make two tables and do the join after log in. Cache the extra facts about the user after they're logged in.
You should have a User table with these columns:
Id, Name, Lastname, Email, Password, IsAdmin
With a Student table:
UserId, Status, Sex, ...
A Student must also be a User - this will reduce duplication of data.
If you need more permissions than IsAdmin then remove that column and make UserPermissions and Permission tables.
If you're really that concerned about a join, then just make everything nullable and in one User table. I doubt it will matter in your use case (this is a much bigger topic).
An administrator is a role played by a person.
A student is a role played by a person.
A person could play one role at a time, or maybe multiple down the road. This is a business rule and should not factor into your database schema.
Use single table inheritance to allow for different types of roles in the same table.
create table people (
person_id int primary key,
given_name varchar(...),
surname varchar(...),
password varchar(...)--consider a `users` table instead
);
create table roles (
role_id int primary key,
person_id int not null references people(person_id), --use the long-hand foreign key syntax for mysql
type varchar(...), --admin or student
status varchar(...), --consider PostgreSQL over mysql, as it supports check constraints
sex varchar(...)
);

Limit many to many relationship by number in Sql

Three tables: users, roles and a pivot table (many to many) role_user.
user:
- id
- name
role:
- id
- name
role_user
- id
- user_id: foreign key link to user
- role_id: foreign key link to role
If I wanted to limit the amounts of maximum roles a user can have to only 1 for example, I could put the role_id foreign link on the user as a role_1 field instead of using a pivot table of many to many.
users:
- id
- name
- role_id_1
The same goes if I wanted only two roles per user.
users:
- id
- name
- role_id_1
- role_id_2
What if I wanted to limit the amount to 1, 2 or something else using a pivot table (Not using foreign role links on the user table) ? Is there an option for that in sql ?
Something like a composite unique index option including role_id and user_id in the pivot table, but instead of a constraint on the uniqueness, a custom constraint on the limit of the user_id number of appearances.
There is a way you can implement this in SQL without triggers. It is a bit complicated, but you could do it.
It starts by adding another table. Let me call it RoleNumbers. This table would consist of one row for each possible role for a user. So, you set it up with 1, 2, or however many roles you want.
Then for the junction table:
create table UserRoles (
UserRoleId int not null auto_increment primary key,
UserId int not null references users(user_id),
RoleId int not null references roles(role_id),
RoleNumber int not null references RoleNumbers(Number),
unique (UserId, RoleId),
unique (UserId, RoleNumber)
);
This uses my naming conventions. I have no problem with having a synthetic key on a junction table.
When you insert a new record, you would have to assign a value to RoleNumber that is not already being used. Hence, you get the limit. The most efficient way to do this is via triggers, but that is not strictly necessary. You could do an insert as:
insert into UserRoles(UserId, RoleId, RoleNumber)
select $UserId, $RoleId, coalesce(max(RoleNumber), 0) + 1
from UserRoles
where UserId = $UserId;
delete would require a separate query for maintaining the numbering scheme.