Referring to super parent or as a separate entity? - mysql

I have this person table as super parent,
id
firstname
lastname
email
telephone
...
...
and user table as a child
id
person_id (FK)
password
username
screenname
...
...
They must be 1:1 relationship, because an user cannot be repeated twice. and so the email in the person row must not be repeated twice.
Then I have this message table which stores messages from anyone,
id
firstname
lastname
email
telephone
subject
content
...
...
but you can see that firstname,lastname, email,telephone are duplicated in message table.
so I am thinking to refer it to person table like this below,
id
person_id
subject
content
...
but then it does not seem right, as a person with the same email, name, etc can send message to me as many times as they want. so the details he/she provides can be repeated.
so should I make message as a child of person the parent or they should be separate entities?
or any better suggestions to solve this problem.

You have to decide what you want your system to do. Do you want old messages to reflect someone's new name or do you want each message to have the name (and other details) which were in effect when the message was created?
If you want the system to only reflect the current personal details then all your message needs is a foreign key to PERSON.
If, on the other hand, you want your messages to look the same way for all time, even if the person who sent them changes their name, email address or other details, then you have to find a way to keep the historical information. Two obvious choices would be (i) denormalize the person details down to the message - as in your current design or (ii) keep a history table of PERSON with snapshots of each combination of personal details with MESSAGE referring to the appropriate person history record with a foreign key.

Related

MySQL user belongs to organization

I have a user table setup where a user can either belong to a Supplier or a Customer organization, which can have multiple users.
My original idea for the User table was to have a customerID and a SupplierID in the user table, out of which one will be filled, based on the organization the user belongs to. This does however not feel right, but I feel like maintaining two linking tables for this is overkill as well.
What would be the best practice in this case? I do not expect there to be any more organizations added in the future, but I do want to futureproof the application, by allowing multiple users to belong to the same organization.
you can design user or organization table with a column organization type which has value: supplier/customer and a column for organizationId

Display details when user click table row

I have following tables in my Database:
Student (student_id, email, name, ...)
Course (course_id, course_name, ...)
Enrollment (student_id, course_id, marks,...)
I Want to implement this functionality:
When admin want to search list of all students in particular city,
the list is displayed as HTML table.
This can be implemented by just querying student table.
When admin click on any row (from the table we have displayed in 1.)
then admin should see list of all courses the student has enrolled
in.
My question is how should I implement this?
I can think of following ways:
Way 1:
https://stackoverflow.com/a/45135144/3494107
I need to have some way to identify which row admin has clicked, for this I can pass the student_id also in the table in result for 1 (display list of all student) but as student_id does not convey any information to admin about student I can just hide it in data-* attribute of <tr> or in <a href=/enrollment/${student_id}> so that I can use this to identify which row admin has clicked. Some of my friend told me that I should not expose surrogate key, this is bad for security. So is there any way I can associate this student_id to table row but hide from the user or it is OK to expose surrogate key content to user?
Way 2: I can create a temporary table containing all student from particular city in DB and assign the row ID to it. Now in result I can add this row ID for each row into data-* attribute. This row ID does not convey any information about what is actual student_id and I can use this row ID to query temporary table to get actual student_id which I can use to search in enrollment table. Now I need to delete this temporary table when user navigate away from current page (go to other functionality), now how should I detect when user have moved away from this page?
I want to understand what security issue I can have if I expose surrogate key to user?
No security issues as such if you expose the student_id but at business point of view it's not much acceptable.
If these tables are only viewed by admins then it is not a problem in either way.
If these are viewable by even by a guest then better not expose the student_id. Not for the security of your database but for the security of your business. It might expose your strength and weakness.
You can use student_registration_no instead. It might be slow, considering a VARCHAR entry, but not humanly detectable.

Link field values and ID to another table?

How do I link or add the field with all my users called "username" from my main table to another table so I can run checks and compare values without having to add a ton of rows to my main table? This would be a much cleaner and more organized setup.
Table called login_users. This is my main table that stores their basic information
username email password
Anthony user#email.com
Josh user#email.com
Tsuyoshi user#email.com
Table 2 called badge_status. This table will hold their status with whether or not they have unlocked an achievement on my site. I want to bring in the usernames.
username badge1 badge2
Anthony locked unlocked
Josh unlocked locked
Tsuyoshi unlocked locked
Also, could table 2 automatically be updated with a new user when they sign up since all new sign ups are imported into the first table. As a side note, I am using phpmyadmin.
Thanks for any help with getting this set up. Very much appreciated.
I think you should normalize your data by using the following schema instead:
login_users [Table]
username
email
password
badges [Table]
BadgeId int PRIMARY KEY
BadgeName
... (any other relevant columns)
users_badges [Table]
username (foreign key constraint to username column on the login_users table)
BadgeId (foreign key constraint to BadgeId column on the badges table)
This will allow you add as many badges as you want without having to ever change your database schema or scripts.
I don't really understand why you are separating out these tables. In theory, there is a one-to-one relationship between the two. Your query "could table 2 automatically be updated with a new user when they sign up since all new sign ups are imported into the first table" further supports the argument why splitting these tables simply creates unnecessary overhead.
Other sources of overhead include overly complicated JOINs to get the data out and the need to add an additional unique constraint on badge_status.username as well as a foreign key.
If you truly wish to separate out these tables, I would suggest the following setup instead which makes querying for specific badges and adding new badges very easy:
login_users: username, email, password, ...
badges: id, name, description, ...
users_badges: username, badge_id, status, unlocked_date, ...

How to handle optional fields in MySQL?

I have a MySQL table that records classified listings. We don't force users to join to post a listing, and therefore the listing will not always have a user_id associated with it.
I therefore need a method of recording the poster's email if they are not signed in.
Is it bad practice to create a column email that will sometimes be blank and sometimes be filled?
Or is there a better way to go about this that I don't realize?
Is it bad practice to create a column
email that will sometimes be blank and
sometimes be filled?
It is not a bad practice, no : juste use a NULL column -- that's why they exist ;-)
See 12.1.17. CREATE TABLE Syntax : in the column_definition part of the create table query, you can specify NULL or NOT NULL.
BTW: Using NULL, which literally means "no value" is better than using some kind of "impossible value", like an empty string : NULL really means "no value", and make your point obvious -- while an empty string could mean an error in your code.
And I don't really see another "logical" way, actually...
Note, though, that you'll have to handle a NULL value for the email, in your application's code, of course ;-)
this is exactly what NULL is for. but you already knew that because your user_id column will also sometimes be NULL, right?
I think the approach you have laid out is perfectly acceptable. As longneck points out, thats what NULL is for in SQL databases.
However, if you're truly concerned about it, you could save space (possibly a significant amount, depending on the column type and number of rows) if you use the user_id column for the userid and the email address, and then have another boolean column, say is_email to distinguish which type of value is stored in the user_id column. This may simplify things for you because it is likely that your application does not care, in many places, whether the data is actually a user_id or an email address.
I have a MySQL table that records classified listings. We don't force users to join to post a listing, and therefore the listing will not always have a user_id associated with it.
I therefore need a method of recording the poster's email if they are not signed in.
What is the business key of your user entity? Or, more directly: what is your user entity? Is every distinct email address a key for a User entity with some users having registered and their email set in some profile, and others not registered and giving an email address every time they post? Or do you have two distinct entities, RegisteredUser and UnknownPosterWithEmailAddress, with their attributes stored in separate places?
In the latter case, you would use a NULLable user_id and a NULLable email field, like you suggested, but then queries like "for a given post, find the email address the reply should be sent to" are going to be awkward, e.g. a list of all post with their respective reply addresses will look like this:
select post.id,
case when post.user_id is not null then user.email
else post.email end as email
from post
left join user on user.id=post.user_id;
This can get real messy after a while.
I'd rather use the former approach: each row in User is a dsitinct poster, with an non-NULLable unique email address, and a surrogate key as foreign key in posts:
create table user(id integer primary key,
email text not null unique,
is_registered boolean default false);
create table post(id integer primary key,
user_id integer not null references user(id),
content text);
If a non-registered user enters an email address, you look it up in the user table, and retrieve the user.id, adding a new entry in user if necessary. As a result, you can answer questions like: for a given email address, how many posts has this user made in the past week? via the foreign key field, without having to compare strings in some NULLable attribute field.
When a user chooses to register, you can add the registration data either in user itself or in some separate table (again with user.id as a foreign key, some might argue that a boolean field is_registered is actually redundant then). Added benefits:
If he has posted before under the same email address, now all of his old posts become associated with his new registered identity automatically.
If the user changes his email address in his profile, all replies to older posts of his "see" the new updated email address.

Should I maintain one or two unique IDs for a dual-role user?

Apologies if I wasn't able to describe the problem accurately in the title. My scenario is as follows.
My site operates as a platform to connect vendors and buyers. Vendors list down the goods/services they have available and buyers are able to purchase goods/services from them.
New buyer (user) registration is straightforward in that their information gets stored in users tables (users, user_profile, user_history etc.) tied together with a unique user_id. What I'm having difficulty wrapping my head around now is that I require vendors to register as well (for verification purposes,) and that vendors can also be buyers.
My users table is like so:
user_id <--- primary key
name
email
...
and a related table may look like so:
transaction_id
user_id <--- foreign key
date
amount
...
My initial thought for the vendors table:
vendor_id <--- primary key
user_id <--- foreign key
vending_name
registration_number
...
and a related table:
product_id
vendor_id <--- foreign key
name
price
...
My question is, would it be best to have this vendor_id to link up all the vendor-related tables or should I stick with using the user_id for everything?
Thanks.
It depends.
Think of this scenario, could a user ever become a vendor (or vice versa?) if so then it's best to plan your data models around a base user and add attributes or flags (in a separate table or field). This way, you can add/remove privileges.
i.e. Have a separate tables called "flags" "flagmappings"
//flags
flag_name <--- 'Vendor', 'User'
//flagmappings
user_id <--- foreign key
flag_id <--- foreign key
This structure gives you a few benefits:
For any given user you can search flagmappings and then determine what privileges a user might have.
All your login/authentication logic is the same for all users/vendors (i.e. you don't have to split/special case different tables if it's a vendor or a user, all the base information is in the same place).
If a user needs to become a vendor or vice versa you simply add that flag to the user.
If you need to create yet another type of user (i.e. administrator, manager, etc.) it's just another entry in the flag table.
If I were you, I would just stick with the users table for everything (as long as you don't have a gazillion vendor-specific fields). It just makes things cleaner. Then, you might have a 'is_vendor' field in the users table.
Or if you want to go even more sophisticated, you could implement roles with something like this:
users Table
id
firstname
etc...
groups Table
id
title
etc.
user_groups Table
user_id
group_id
Personally, I would go with the second option because it allows for more role-based permissions, such as admin, editor, moderator, buyer, seller, super-buyer, super-seller, etc.