Users table to Users and User Preferences. Is this normalized?

Deadly 提交于 2019-12-24 12:51:18

问题


I have a table called Users that has a growing list of preferences. These preferences could includes ReligionId (which would key off to another table that contains the list of religions).

The list of preferences is growing. I want to split it off the Users table into 2 tables. The strategy that I think would work well is to make a separate table called UserPreferences. I'm wondering if doing this is in line with the rules of normalization. Here is an illustration to make things a bit more clear.

Is this normalized? Are there better ways? All comments appreciated.

EDIT: How UserPreferences key off to other tables:


回答1:


At a minimum you could just have Users and Preferences. There should be a one to many relationship between users and preferences. One user can have many preferences. You could also split out the email addresses into another table - so that one user could have multiple email addresses - you can have a flag to denote the primary one. The DDL would look like:

    create table Users
    (
       UserId int,
       Age int
    )

    create table Preferences
    (
        PreferencesId int,
        UserId int,
        ReligionId int,
        PersonalDescription varchar(2000),
        HairColor int
    )

    create table EmailAddresses
    (
        EmailId int,
        UserId int,
        EmailAddress varchar(100),
        IsPrimary bit
    )

    create table Religion
    (
        ReligionId int,
        Name varchar(200)
    )

Insert into Religion (ReligionId, Name) Values (1, 'Jediism')
Insert into Religion (ReligionId, Name) Values (2, 'Sithism')
Insert into Religion (ReligionId, Name) Values (3, 'Yuuzhan Vong')
Insert into Religion (ReligionId, Name) Values (4, 'Pinacism')

Insert into Users (UserId, Age) Values (1, 30)
Insert into Users (UserId, Age) Values (2, 18)

Insert into Preferences (PreferencesId, UserId, ReligionId, PersonalDescription) values (1, 1, 1, 'a description')
Insert into Preferences (PreferencesId, UserId, ReligionId, PersonalDescription) values (2, 1, 4, 'another description')
Insert into Preferences (PreferencesId, UserId, ReligionId, PersonalDescription) values (3, 1, 4, 'even another description')




回答2:


Some folks are recommending to store the preferences one per row. This is called an Entity-Attribute-Value table, and it is not normalized. Some people say EAV is "more normalized," but they're mistaken. There is no rule of normalization that encourages EAV as a design in a relational database.

One practical way you can tell it's not normalized is that you can no longer use a foreign key constraint for your religion lookup table, if all values of all preferences share a single column in this preferences table. You can't make a foreign key constraint restrict the values only on rows for a particular preference type -- the FK constraint always applies to all rows in the table.
Basically, Entity-Attribute-Value breaks SQL's support for constraints.

The only normalized design is to define a separate column for each distinct preference. Then you can define data types and constraints appropriate to that preference type.

If you really want to understand relations and normalization, read SQL and Relational Theory: How to Write Accurate SQL Code by C. J. Date.

Each column represents selections from a set. A set can be the set of integers, or the set of religions, or the set of email addresses. A row in a table is a pairing of sets that "go together," for example a given user has a name, and an birthdate, and a religion, and an email address, so those values are matched up together into one row, and together they describe something that exists in the world, i.e. a human being with those attributes.

What this means is that in each row, you have one value chosen for each of the columns, i.e. from each of the component sets that are references. And each column contains values only from one set. In the religion column, you can only choose religions, you can't also put favorite color and mother's maiden name and shoe size into the same column.

That's why EAV is bogus from a relational perspective, because it mashes values from any and all disparate attributes into the same column. It's more like a spreadsheet than a database. Not that I'm saying relational is the only way to store data. It's just that if you're asking if EAV is normalized, and normalization assumes as a prerequisite that the data is relational, then no, EAV is not relational and therefore cannot be normalized.




回答3:


If you say that you have growing preferences then I would suggest you make a new table for preferences and add the FKey to the UserPreferences

Users Table - userid, email, age, alternateemail ...

Preferences table - Preferenceid, preference_Value, active, required

Users Preferences table - userid, preferenceid, preference_data

Now you can have your ever growing list of preferences in the Preferences table and connect it to the UI, and the two columns - active, and required will help you to control your form easily from backend.

And in user preferences table you just reference the preference id with the user id and store the data input by the user for that preference.

I hope this was clear.




回答4:


It doesn't make sense to split a single table in to two tables. Only time you split like this is some users doesn't have Preferences at all.

Creating a new column - whenever new Preference comes up - is not a good idea.

If you think Preferences will grow in the future, you can use the following method -




回答5:


A normalized userPreference table would contain the userID, preferenceID, and preferenceValue. Preferences would list all of your preferences (email, age, etc) on one row with an ID as the PK, plus whatever descriptive information you wanted to add.


since the data types of the preference values differ, you can declare it as a string/varchar, or, if you really want, have different preference values for the different data types, like 'prefValInt,' 'prefValChar,' etc., where only one column would contain a value.

I usually just use a string.


Now, if you want to enforce referential integrity, like in your example above, you're back to having each preferenceID in a different column, so you might want to keep those preferences in your main table and all of the other ones in the lookup table.


any column that needs RI enforced, such as religionID and hairColorID, can go in the user table, or can go in a userPreferenceRI table with a 1-1 relationship with the user table. any column that does not have RI enforced, such as age, dateOfBirth, accountBalance, emailBody can go in a userPreference table with the PK being the userID and the preferenceID and a 1-many relationship with the user table.

HTH


you should also take into account the likelihood of preferences existing. For required fields, such as ageAtPointInTime or dateOfBirth, you should store them in the user table. For preferences which are sparsely populated (most don't have an answer,) you should put them in a lookup table.

    user: userID, requiredFld1, requiredFld2
    preference: preferenceID, preferenceName, preferenceDescription
    userPreference: userID, preferenceID, userPreferenceVal as varchar(100) 
(list of columns never changes)
    userPreferenceRelated: userID, religionID, hairColorID, otherPreferenceID 
(list of columns grows over time)


来源:https://stackoverflow.com/questions/25536617/users-table-to-users-and-user-preferences-is-this-normalized

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!