Best practice store email unique MySQL and Validate JS - mysql

I have a table where email is a unique key, the point is... when the user get deleted in the manage form, I do an update, inserting "1" in a column called "deleted", doing this I keep the data and the history of that user... But if I have to add a new user with the same email, Bang MySQL catches me
So.. my question is, the best practice is?
Do a remove in table when user get deleted, losing the history of that user
Remove the unique key in the column email, and keep the validate only in JS for prevent duplicates emails
Another one...
Thanks for your time

You can restrict emails to being unique only if not deleted with a virtual column:
create table user (
email varchar(320),
deleted tinyint,
undeleted_email varchar(320) as (if(deleted,null,email)) unique
);
fiddle

You could reverse the logic and instead of storing a nullable deletion mark, store an active mark. Use a check constraint (in MySQL 8+) or a trigger (in lower MySQL versions which don't enforce check constraints) to restrict the possible values of the active mark to one (non-NULL) value (and NULL). Then put the unique constraint on the e-mail address and the active mark combined. That way you can have multiple rows with the same e-mail address and a NULL active mark but maximally one with that address and a non-NULL active mark.
CREATE TABLE user
(id integer,
email varchar(256),
active tinyint,
PRIMARY KEY (id),
CHECK (active = 1),
UNIQUE (email,
active));
db<>fiddle
But as a non technical side note, check, if you're legally allowed to keep the history of a user when they delete their account according to the data protection laws applying to you. They may have the right to expect that everything is deleted when they delete their account.
And you could also consider, no to create a new account, if a user comes back, but instead offer them to reactivate their old account.

Related

Should I lock the table when creating user?

I want to create a user into User table.
These are my process.
continue when email and nickname are not exist
creates a user
I think if I didn't lock the User table while creating a user then email and nickname can be duplicated.
Any ideas?
Avoid locks where possible. Instead, use a unique index, and simply insert the user. If the user or email exists, your query will return an error similar to:
Error Code: 1062. Duplicate entry 'john.doe#example.org' for key 'unique_email'
This should be done with 2 separate indexes. One for email, and one for users. This has the following advantages, and almost zero disadvantages:
It enforces database consistency. At no point will 2 users have the same email address, nor the same username.
It avoids unnecessary locks.
It avoids technical debt. Let's say down the line you add a user importer. In the importer you fail to check for duplicate accounts, or add in locks, or forget to check if the username or email exists. Your importer will work, and your database will now contain entries that duplicate each other.
I'd try to create a combined unique key on email and nickname
CREATE UNIQUE INDEX some_index_name ON user_table(email , nickname)
Edit: To address the comments below, we should as well create 2 more unique indexes for email and username, to make sure 2 users with separate emails can share the same username and vice versa.

How to save login details of different kinds of users into one table

I have created 2 separate tables for admins and users in my database. I want to save user and admin login details (ip address, user_agent, connection time etc) into one table. Is the only solution to create two fields one for admin ids and other for user ids in this table (like below)?
CREATE TABLE login_detail (
id int NOT NULL AUTO_INCREMENT,
admin_id int,
user_id int,
ip_address ...
...
PRIMARY KEY (id),
FOREIGN KEY (admin_id) REFERENCES admin(id) ON DELETE RESTRICT ON UPDATE RESTRICT,
FOREIGN KEY (user_id) REFERENCES user(id) ON DELETE RESTRICT ON UPDATE RESTRICT
)
If an administrator logs in, his id will be stored in admin_id and user_id will be empty. If a user logs in, his id will be stored in user_id and admin_id will be empty. What do you suggest (generally)?
I believe that ermagana understood you were converting those two tables into one table, not accessing those two tables through the new, third table. At least, that is what I assumed until I saw your response. Am I correct? If so...
In general, there is really no reason why this wouldn't all be in one table with a bit-flag indicating admin authority, as ermagana responded. I believe that would be the most common implementation, though certainly not the only option.
Your implementation using three tables, as I understand it, will require extra coding and certainly more database activity. You will need to check if the user is a user and, if not, then check if the user is an admin. Also, how are you going to ensure that the same user isn't in both tables without extra coding and database activity? At least how I understand it, it appears inefficient and error-prone.
Perhaps I don't understand it at all. If so, please clarify.

How to add more data to a table that already has primary key?

I am new to Mysql so go easy. Forgive the lack of knowledge in this area.
But I have searched everywhere and it's stupid I can't just find this simple answer. Trying to make a fun app to promote pages, earn points, PPC type ads for fbook blah blah...
I currently have one {table1} with user data.
UID,
fname,
lname,
date added
And table2 for submitting user links for the ads to return on a page,
it only has
primary from the UID
and 1 col right now able to add links to.
With the primary key I want either username or uid but must be able to add more to the existing primary key so I can call the user and all links. I can add like this but of course have to delete myself to add more to the table...
$query = "INSERT INTO {$table} VALUES ('{$userid}', '{$user_link}')";
mysql_query($query) or die('Error updating database');
Then, say they add another one later
if new submission check existing then
add new column to existing uid... link#2=http://
What am I missing. It's hard to even word the question that's why I am putting this here for search results! HELP!
Your table can't have a database primary key on UID. By definition UID as a primary key MUST be unique. So either you need.
a COMBINED KEY UID & USER_LINK (ORACLE thinking)
No Key at all (It works; but then you can have duplicates )
A generic AutoNum key which adds 1 for each record (MSFT thinking)
When you say something is a Primary Key, you mean the value will NEVER be null and it will ALWAYS be UNIQUE in the table. You have to be careful with this; somethings you think are unique, in fact are not.
In this case the UNIQUE key is defined with user links the same user has no need to have the same link (right?) so you could make a combined key between the two.
Remove the PRIMARY KEY on table2, which is, by definition, unique. Use a regular index as a FOREIGN KEY back to table11.

Create new user with email as a soft deleted user

I am using ActsAsParanoid for soft deleting users.After deleting(soft) a user, my client wants to create user with same email id.But it generating unique field error since email column is unique.So my question is can we set the uniqueness for email column only if the deleted_at column is null.
Pls reply if u dont understand my question.
I suppose you could change the uniqueness constraint of your users table to be:
UNIQUE (email, deletion_date)
This would effectively:
For standard (non-deleted) users, guarantee they have unique email addresses, since their deletion dates would presumably all be NULL.
For deleted users, not make any guarantee about email addresses, since they all have unique deletion dates.
For new users, allow them to use an email address that a deleted user has, since the new user will have a NULL deletion date, while the deleted user has a value there.
Ah, just change old email to something like
Me#yourmail.com_deleted
That way if you need to view the old email it's everything before the underscore deleted.
In other words here have new user create new account.
Probably have a mutator in the background add the underscore deleted on the old account.
Underscore deleted just an example.

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.