Updating in a many-to-many relationship - sql-server

I have a many-to-many table that stores a record for each allowed role a user can have. If a user updates his roles (add, and removes) roles how should I handle this?
Should I delete all the users roles first and then add the selected ones? Or do some sort of matching?

There are many ways to skin this cat, a few techniques I can think of:
1. Delete all roles and re-insert
This is a straight-forward approach. Remove all the roles for the user and just re-insert. Normally the user only belong to a few roles (less than 10). Also, there is a good chance that no other foreign-keys link to this many-to-many table.
2. Keep track of the changes and apply only the changes
This is more work but more efficient, even if just slightly in this case. Tools like ORMs makes tracking and applying these type of changes a breeze.
3. Apply the changes as the user makes the change
In this case I assume that it is acceptable to apply the DB changes as the end-user associates the user to roles. Perhaps it is a local database and each transaction is short-lived. But I guess this is a unlikely scenario.
I don't think there is anything wrong for this particular case to delete and re-insert.

If a person removes a role why not pass the userID and roleID and remove that one record?
Why would you want to delete all roleID's for a specific userID and then readd them again?
From my comment above, pass two params:
UserID and RoleID
Then you can delete / extract that single tuple.

Related

Dealing with 3NF in terms of database domain modelling where attributes are added knowing they create transitive dependency

I am currently working on setting up a database domain model, where in terms of normalization I will be challenged due to transitive dependency. However, for this particular model it is a choice, that we choose to add such transitive dependency for a reason, and I am wondering how you would go about dealing with such cases in the aspect of normalization?
Let me show what I mean:
I have a table called UserSubscription that have the following attributes:
id {dbgenerated}
created
user
price
currency
subscriptionid
The values for:
price
currency
Depend on the subscriptionid, which points to a second table Subscription (in which the subscriptionid is a FK reference to this tables PK). One might say why, would I even consider including duplicate values from the Subscription table into the UserSubscription table? Well the reason is that the Subscription might change at any point in time, and for reference we want to store the original value of the subscription in the UserSubscription so that even if it changes we still have the values that the user signed up for originally.
I know from the perspective of normalization, that this transitive dependency I create should be fixed, and ideally I would move the values back into the subscription table, and just not allow the values to be modified, and instead create a new subscription whenever it is necessary.
But ideally I do not want to create new subscriptions every time something needs to change in those that exist, simply because it is expected these change often - following say market competition values. At the same time for every new subscription created any user will have more to choose from.
This also means that if we no longer want to use a subscription, we would need to: Remove it, and Create a new one. This can be fixed by simply Updating, since we will no longer need the old one anyways.
The above is a school project, I just wonder whether it would ever be "ok" in terms of normalization to choose such approach, when I choose to do so by choice, and to reduce the tasks associated with removing and creating new subscriptions when I expect these would change frequently.
why don't you instead create a M:N table (mapping table) USER_SUBSCRIPTION where you will have the relationships between USER and SUBSCRIPTION ? You can store all values there historically, and don't have to remove/create anything with the change.. it the user decides to opt-out, you only update the flag_active, flag_deleted, flag_dtime_end, whatever works for you...
Here is a simple model for demonstration:
USER
id_user PK
name
... other details
SUBSCRIPTION
id_subscription PK
name
details
flag_active (TRUE|FALSE or 1|0 values)
... other details
USER_SUBSCRIPTION
id_user FK
id_subscription FK
dtime_start -- when the subscription started
dtime_end -- when the subscription ended
flag_valid (T|F or 1|0) -- optional, will give you a quick headsup about active subscriptions ... but this is sort of redundant, for you can get it from the dtime_start vs dtime_end .. up to you
This will give you a very generic (and therefore flexibile / scalable) model to work with users' subscriptions ... no duplications, all handled by FK/PK referential constraints, ... etc

How can I fit these 3 columns into one?

For a project, I have a database with some tables.
All of them are related between them. The table organization has a relationship with offer and user, etc.
However, I have some columns that only serve to link two tables together.
Take a look at the diagram. I use users_interests to link the user to his interests. Same thing for badges and group.
It doesn't really feel efficient. When I try to get the interests of a users, I must first go through requesting the user interests and from that, require the interest details.
Is there a way that I can request the interests of an user without having to go through a second table ?
https://dbdiagram.io/d/5da3f119ff5115114db53551
There's a couple things you should consider when looking at this question/functionality and what you're going to be doing with the data.
Do you have a unique set of interests that will remain the same or be added to, without duplicates?
Do you need to have multiple interests for a single user?
If you answered "yes" to both of these questions, then you should leave things the way they are. You'll be able to reuse the same interests entry for multiple users as well as each user being able to have multiple interests.
If you only want one interest per user, but want to keep a "master list" (aka: lookup table) of interests, then you can move the interest_id to the users table.
If you don't care about duplicates, but you still want each user to have multiple interests, move the name column to the users_interests table.
Finally, if you don't care about duplicates and you want each user to have a single interest, move the name column to the users table.
FYI, how you currently have the tables structured will likely take up less disk space for a large amount of users.
It's unclear what you're trying to do, so I included all options. Each option has it's own set of pros and cons, and each will be required of some other project or another at some point. You might want to learn the difference and reasoning behind why you would use one option over another now, so you don't have to think too hard about it later.
You can do it if you will make interests like this
id
user_id
name
but then you will lose uniqness of your interests, you will have many rows with the same name only because they connect to different users. Now db is perfectly ok according my understanding...It is as it should be

Database paid users and trial users in same table

If you had to design a database with paid users and trial users would you put them in the same table and differentiate between them with a field? Or would you put them in two separate tables?
Or would you do the best of both worlds and put them in the same table but create two views 1) PaidUsers and 2) TrialUsers
Thanks!
I just express some performance considerations in following opinions.
In single user query(ex. login check, or data retrieving for single user), there are not significant differences between these two strategies.
But if you need some statistic data, for example, one for paid users and another for trial users. And seperating to two tables may be a good idea.
Otherwise, if you need some statistic data whatever paid users or trial users, single table may be a good idea.
What if you need both of scenarios? Well, I think that would be a case which some common attributes exist between two kinds of users.
These common attributes should be put in one table, and dedicated attributes for particular users should be put in 'sub-table' inheriting from former table. Just as vonPetrushev said.
Since your paid users would probably be related to some additional data, but still have the same fieldset as non-paid, the correct way to do this is [is-a] approach:
User
id
username
password
fullname
...
Paiduser
user_id [fk->User::id]
account_id
.... [other addidional data]
EDIT: Now, the trial users will be all records in User that does not have entry in Paiduser. I'm assuming that Paiduser fieldset is a superset of the fieldset of a trial/normal user [User].
EDIT 2: To get a list of trial users, which are 'set difference' between User and Paiduser, the following sql should work:
select u.*
from (User as u
join Paiduser as p on u.id<>p.user_id)
The best solution may depend on database type. My experience is with MySQL and SQL Server. I've always put all users into a single table. Then differentiate as needed using fields. This could apply to paid/ unpaid or anything else. This solution meets 3NF standards and seems easier to me for maintenance etc. What reason would there be to use multiple tables?

Entity Deletion Strategy

Say you have a ServiceCall database table that records down all the service calls made to you. Each of this record contains a many to one relationship to Customer record, where it stores which customer made the Service Call.
Ok, suppose the Customer has stop doing business with you and you do not need the Customer's record in your database. No longer need the Customer's name to appear in the dropdown list when you create a new ServiceCall record.
What do you do?
Do you allow the user to delete the Customer's record from the database?
Do you set a special column IsDeleted to true for that Customer's record, then make sure all dropdown list will not load all records that has IsDeleted set to true? Although this keeps the old records from breaking at innerjoins, it also prevents user from adding a new record with the same name as the old Customer, won't it?
Do you disallow deletion at all? Just allow to 'disable' it?
Any other strategies you used? I am guessing everyone have their way, I just need to see your opinions.
Of course the above is quite simplified, usually a ServiceCall record will link to many other entity tables. All of which will face the same problem when they are required to be deleted.
I prefer to set an IsDeleted flag, one of the benefits is you can still report on historical information (all teh data is still there).
As to the issue of not being able to insert another customer with the same name, this isn't a problem if you use an ID column (eg CustomerId) which is generally auto populated.
I agree with #Tetraneutron's answer.
Additionally, you can create a VIEW that lists only the active customers, to make it more convenient to populate drop-down lists and such.

DB Schema Organization

I'm currently in the planning phase of building a scheduling web app (for volunteer staffing of events), and I've got a question for those with more experience.
Background:
There's a calendar of events, and any user at any time can register for any of the events. At a later time, but before that event, one of the admins will step in and select a "Staff List" out of those that registered, and the rest will be put into an "Alternate List".
What I've been thinking so far is that there will be an Event table, a User table, and then three others:
UserEvent
Maps users to events they registered to. Does not imply either the Staff nor the Alt list membership.
UserStaff
Maps users to events they registered to, and also happen to be staffing.
UserAlt
Similar to UserStaff
The question then becomes two part:
Is this a good way to do it?
Should each of those three associative tables have the user id and the event id?
That second question is really the one I'd like to see discussed. That seems like a lot of duplicated material (everything in either UserStaff or UserAlt will always be in UserEvent), so I was thinking of creating a unique key for the UserEvent table, in addition to the composite key, that the other tables (UserStaff and UserAlt) will refer to. On the plus side, there is less duplicated content, on the down side there's an intermediary table (UserEvent) that needs to be referenced in almost every query this way.
Hopefully I've been clear enough, and thanks in advance.
I would have the following tables:
User (UserID, firstname, lastname, etc.)
Event (EventID, Name, Date, Location, Capacity, etc.)
EventRegistration (EventRegistrationID, UserID, EventID, ParticipantTypeID, etc.)
ParticipantType (ParticipantTypeID, Name)
ParticipantType.Name is one of "participant" or "staff".
This seems good, although you might want to consider combining your User - Event association tables into one, and having a column on that table that indicates the purpose of the association, i.e. Event, Staff, or Alt. This would effectively obviate the need for the duplication you describe in the UserEvent tables, since Staff and Alt could be considered to be supersets of Event for most purposes.
One benefit of this approach is that it allows for there to be multiple types of User - Event associations, such as if you have a User who is a Staffer for an Event but not a Participant, or a User who is just an Alt; this approach saves you from having to enumerate all the possible combinations. Now, if your design explicitly specifies that you can only have a certain set of User Participation types, this might introduce a level of dissociation you don't want; you may prefer to have explicit constraints on the set of participation levels that a User may have on an Event. If you don't have that tightly specified set, on the other hand, this system allows for adding more Participation roles easily (and without disturbing existing Participation roles).
Not a direct answer to your question, but here's a site I like. It's got tons (and tons) of sample schema. I generally don't use it as definitive (of course), but sometimes it will give me an idea on something I wasn't thinking of.

Resources