How to store all user settings in one database with a unique id - sql

Im making an app where I have a server-side sql database to store the user settings of all users.
Im not sure how to make each user unique, so that the database knows who is who.
The database is storing these user data for each row: id, email, county, age and gender.
So im thinking the best way is to make the user unique to he/she's email - which is unique - so that the when the settings are updated or outputted, the sql knows what row to fetch.
How should I go about with this?
And how would i then output the right data to the right user?

An entity in the database should have a primary key. I understand that in your design the id field is going to be the primary key. Usually this is an auto-generated integer. This is called a surrogate key In this case you need to tell to the table that the email field must be unique as well. You can do that by creating a unique index for this field. The unique index will prevent the creation of two different users with the same email. Going with this approach you can query the table checking either for id or for email.
An alternative is to have natural key. In this case, email would be the primary key of your table, so you wouldn't have the id field. Going with this approach you can query the table checking either for email, which is the unique identifier of each user.

Related

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.

How to make a row's value unique across two columns?

Suppose I have two columns, Column A and Column B. Column A is required, and Column B is optional. If Column B is specified, I'd like to make sure that its value is not found in Column B (easy) OR Column A (seems much harder) outside its own row. Likewise, if Column A is changed, I'd like to make sure that its new value is not found in Column B or Column A, outside its own row.
So far, the closest I've gotten is the exclusion constraint, but that doesn't seem capable of comparing Column B to Column A. Is this possible outside the application layer, or am I stuck with an application layer solution?
The use case is that I'd like the following:
Users always have usernames, which are always unique amongst all usernames and emails.
Users sometimes have emails, which are always unique amongst all usernames and emails.
This allows me to know that, for example, if a user logs in with their email address I know which username is theirs. But I also want users to be able to use email addresses as usernames. And more confusingly, I'd like users to be able to specify one email address as a username and a separate email address as the email address on file.
Any pointers?
I think you should have one table for users. This should have a unique, auto incremented user id. You should have another table for logins. This would have columns such as:
UserId
LoginType (email or userid)
Name
This table has a unique constraint on name. In addition, it has a unique constraint on UserId and LoginType to ensure at most one value of each for any given user. You can add additional constraints to ensure that emails really look like emails, for instance.
If you want a separate email associated with the UserId for contact purposes, you can put that in the Users table.
The key idea: move the confusing notion of a login to a separate entity (table) in the database.

SQL Server Management Studio - How to model this database constraint in a Database Diagram

I have a table named Communications which contain a user's contact numbers. This can either be a Home, Mobile or Fax number. I'm storing them all in one table and identifying them using a Type column. (0 = Home, 1 = Mobile, 2 = Fax). Communications table has a foreign key UserId which maps to my Users table to show User to Number relation. I want to have a constraint so that each user can only have at most one of each Type of number. What would be the best way to model this?
I'm using Database Diagram in SQL Server Manager Studio 2008 and would like a GUI-ish answer as opposed to SQL query if possible.
You can add a NumberType table, containing the values 0,1,2 as primary key in column NumberType, and add a foreign key from table Communications.NumberType to NumberType.NumberType. This way table Comunications will only be able to contain values 0,1,2 (or whatever NumberTypes you define).
Then you add a primary key (or unique index, if you want some other primary key) to table Communications on columns NumberType and UserId. This makes sure that each user may only have one number of each kind.
Simply use composite key {UserID, NumberType}
It also a good idea to keep {UserID, PhoneNo} unique and to make sure that a phone number is of one type only; while allowing for more than one user to have the same phone number, say home phone for a family. In that case you can try something like this
Note: implement AK (alternate key) as a unique index.

Having a Login ID and a PersonID in SQL

I am creating an application that will require a user to register and create an account.
Should I use the person's Login ID (this is the email address) as the unique record identifier or should I also create a PersonID (or rec_id).
Why should I (or should not) create a rec_id ?
If you use the email address as a primary key in the Person table and foreign key in the related tables, it will be hard to implement the Change Email feature - instead of a single update, you will be forced to add a new record to the Person, update all the related records and then delete the record with old email.
Of course the person's mail address usually should be unique. But an additional record ID can be used as foreign key in other tables and so will make table joining much easier.

Creating database tables with "either or" type fields

I have a database that tracks players through their attempts at a game. To accomplish this, I keep a table of users and store the attempts in a separate table. The schema for these tables is:
CREATE TABLE users (
id BIGINT PRIMARY KEY, -- the local unique ID for this user
name TEXT UNIQUE, -- a self-chosen username for the user
first_name TEXT, -- the user's first name
last_name TEXT, -- the user's last name
email TEXT, -- the user's email address
phone TEXT -- the user's phone number
);
CREATE TABLE trials (
timestamp TIMESTAMP PRIMARY KEY, -- the time the trial took place
userid BIGINT, -- the ID of the user who completed the trial
score NUMERIC, -- the score for the trial
level NUMERIC, -- the difficulty level the trial ran at
penalties NUMERIC -- the number of penalties accrued in the trial
);
Now I need to be able to store attempts that come from "transient" users. These attempts should not be linked back to an existing user. However, these transient users will still be able to enter a name that displays in the results. This name is not required to be unique in the table, since it does not represent a "real" user.
My first thought was to create a new field in the trials table called name. If userid is null, I would know it is a transient user, but I would still be able to show the name fields in the results. This approach doesn't quite smell right, and it seems like it will make my queries a bit more complicated. Additionally, it seems like I'm duplicating data in a sense.
Another thought was to replace userid with a useref text field that would be some kind of formatted string representing the user. For example, if the value were enclosed in curly braces, I would know it's an ID, i.e. {58199204}. If the value were not enclosed, I would treat it as a transient user. This more accurately represents what I'm trying to do conceptually (i.e. it's either an ID or a transient user string), but it would really complicate my queries.
I'm using SQLite for the backend... It lacks some of the extended features of SQL Server or MySQL.
Any thoughts on these or another approach to the problem?
Without more information about why a transient user can use but not exist in the system, I concur with your idea to:
Add a NAME column to the TRIALS table
Make the USER_ID column in the TRIALS table nullable/optional in order to indicate transient user status
If you could allow a transient user to exist in the system, I would recommend:
Creating a USER_TYPE_CODE table
Update the USERS table to include the USER_TYPE_CODE column (w/ foreign key reference to the USER_TYPE_CODE table)
You can either create a UserType field in the users table, and add "transient" users to the Users table, but this might increase the size of the Users table, or create a UserType field on the Trials table and create an additional TransientUsers table.
This will allow you to distinguish the difference of userid with the UserType field.
I'd like to point out that you really shouldn't use the formatted string approach. What happens if a user finds a bugged input port into your database and inputs "{8437101}" (or whatever user ID they want)?
SQLite lets you mix types in a field. I'd suggest you do as you were thinking, but without the braces. Disallow numeric names. If the userid is a number, which is exactly when it matches an id in the users table, it is a user id. If not it's the name of a transient user.