Suppose I do have a users table in my application. I want to give that user status like active, inactive, blocked, approved, and verified. What should be the best approach for that?
Should I use multiple table columns like active = 1, inactive = 0, etc, or just a single column name 'status' and put that active, inactive, or block status as a value?
From a normalization perspective, you should keep 1-to-1 relationships within the same table.
You can also have a middle table where you store all of the available status values and use a foreign key to that table for each user record to set the status.
Related
I have a requirement in my app where one user can send the friend request to another user. We use SQL Server database as the backend. The structure of the table is like this.
CREATE TABLE FriendStatus
(FriendStatusId BIGINT PRIMARY KEY IDENTITY(1,1),
FromUserId BIGINT,
ToUserId BIGINT,
StatusId TINYINT,
SentTime DATETIME2,
ResponseTime DATETIME2);
I have few questions related to this:
If user A sends a friend request to user B, then the friend request from user B to User A should still valid ? I feel that should be the case, let me know if there is a better way of handling this ?
Is it a good idea to store the users data in a separate table called friends table once User b approves user A friend request ? And Once User B approves User A request then two records needs to be inserted into the friends table with col1 containing user A and col2 containing user B .At the same time should we also insert a record with User B in col1 and USer A in col2 ? Or two records are unnecessary ?
Is it a good idea to store the users data in a separate table called friends table once User b approves user A friend request ?
No, it's almost never a good idea to duplicate data in your database. You can get anomalies where the same data in two places has two different values. Which value is the correct value?
Here's one way to maintain the relationship
User
----
User ID
User Name
...
Friend
------
User ID 1
User ID 2
...
In the Friend table, the primary key is (User ID 1, User ID 2). You would also have a unique index on (User ID 2, User ID 1). It's up to you if you want to have one row or two rows for each relationship.
One row means you have to do two SELECTS with a UNION. One SELECT using the primary key and one SELECT using the unique index.
Two rows means you do a SELECT using the primary key.
You have the same one row / two row choice with the FriendRequest table.
FriendRequest
-------------
User ID 1
User ID 2
Status
Sent Time Stamp
Accepted Time Stamp
...
You can have one row or two rows for each request. In this case, I'd prefer the one row because I could determine which user initiated the friend request.
I'll take a few examples from Facebook to answer.
If user A sends a friend request to user B, then the friend request
from user B to User A should still valid?
No, a dialog box appears You have already recieved a Friend Request from {name}. Also from B's view, The link to Send Friend Request to A should be changed to Respond to friend request with a respective code.
Is it a good idea to store the users data in a separate table called friends...?
No, one record is enough. Additionally you can have a new column to maintain status status={blocked|friends|pending}
Well thats my idea. You are free since the application is yours. Think as a user too.
I have two class, User and Status, while a user will have a number of status, this is naturally Many-to-One relation and can be easily mapped to DB Tables.
However, the requirement also need User to maintain its “current” status, i.e., in the User Table, it need to have a foreign-key to the Status table. The result of this is having two foreign-keys between two tables in the opposite direction.
One obvious problem of this is once the records are inserted into the two tables, I can delete neither of them cause deleting from one table will violate the other table's foreign-key.
What is the best Design for this situation?
in your Status table , add a column that will determine whether this status record is "Current" or not.
** for performance issues , you can set only the "current" status records with '1' value and the rest with null value
you now don't have to use 2 foreign keys , only one - from Status to User.
if you are using hibernate as the post's tag :) you can create a view in the database that will select only the "Current" status records and will have the same structure as the Status table.
connect the view to the User entity using One-to-One relation,
I hope it helped you !
Do you have to keep the status in a separate table ? can it not be just represented by a java enum, and the User would have a status property. Something like this:
public enum UserStatus {
X, Y, Z;
}
public class User {
private UserStatus status;
...
}
Is it better to create tables that store a lot of data that are related to an entity (User for example) or many tables to store said data?
For example:
User Table
Name
Email
Subscription Id
Email Notifications
Permissions
Or
User Table
Name
Email
Subscription Table
User ID
Subscription ID
Notification Table
User ID
Receives?
... etc
Please consider code in this as well, or I would have posted to ServerVault.
From a relational design standpoint what is important is the normal form you're aiming for. In general, if the "column" would require multiple values (subscription_id1, subscription_id2, etc) then it is a repeating group, and that would indicate to you that it needs to be moved to a related table. You've provided very general table and column notes, but taking a cue from the fact that you named "Email Notifications" and "Permissions" with plurals, I'm going to assume that those require related tables.
This question applies to any database table design, where you would have system default items and custom user defaults of the same type (ie user can add his own custom items/settings).
Here is an example of invoicing and paymenttypes, By default an invoice can have payment terms of DueOnReceipt, NET10, NET15, NET30 (this is the default for all users!) therefore you would have two tables "INVOICE" and "PAYMENT_TERM"
INVOICE
Id
...
PaymentTermId
PAYMENT_TERM (System default)
Id
Name
Now what is the best way to allow a user to store their own custom "PaymentTerms" and why? (ie user can use system default payment terms OR user's own custom payment terms that he created/added)
Option 1) Add UserId to PaymentTerm, set userid for the user that has added the custom item and system default userid set to null.
INVOICE
Id
...
PaymentTermId
PaymentTerm
Id
Name
UserId (System Default, UserId=null)
Option 2) Add a flag to Invoice "IsPaymentTermCustom" and Create a custom table "PAYMENT_TERM_CUSTOM"
INVOICE
Id
...
PaymentTermId
PaymentTermCustomId
IsPaymentTermCustom (True for custom, otherwise false for system default)
PaymentTerm
Id
Name
PAYMENT_TERM_CUSTOM
Id
Name
UserId
Now check via SQL query if the user is using a custom payment term or not, if IsPaymentTermCustom=True, it means the user is using custom payment term otherwise its false.
Option 3) ????
...
As a general rule:
Prefer adding columns to adding tables
Prefer adding rows to adding columns
Generally speaking, the considerations are:
Effects of adding a table
Requires the most changes to the app: You're supporting a new kind of "thing"
Requires more complicated SQL: You'll have to join to it somehow
May require changes to other tables to add a foreign key column referencing the new table
Impacts performance because more I/O is needed to join to and read from the new table
Note that I am not saying "never add tables". Just know the costs.
Effects of adding a column
Can be expensive to add a column if the table is large (can take hours for the ALTER TABLE ADD COLUMN to complete and during this time the table wil be locked, effectively bringing your site "down"), but this is a one-time thing
The cost to the project is low: Easy to code/maintain
Usually requires minimal changes to the app - it's a new aspect of a thing, rather than a new thing
Will perform with negligible performance difference. Will not be measurably worse, but may be a lot faster depending on the situation (if having the new column avoids joining or expensive calculations).
Effects of adding rows
Zero: If your data model can handle your new business idea by just adding more rows, that's the best option
(Pedants kindly refrain from making comments such as "there is no such thing as 'zero' impact", or "but there will still be more disk used for more rows" etc - I'm talking about material impact to the DB/project/code)
To answer the question: Option 1 is best (i.e. add a column to the payment option table).
The reasoning is based on the guidelines above and this situation is a good fit for those guidelines.
Further,
I would also store "standard" payment options in the same table, but with a NULL userid; that way you only have to add new payment options when you really have one, rather than for every customer even if they use a standard one.
It also means your invoice table does not need changing, which is a good thing - it means minimal impact to that part of your app.
It seems to me that there are merely "Payment Terms" and "Users". The decision of what are the "Default" payment terms is a business rule, and therefore would be best represented in the business layer of your application.
Assuming that you would like to have a set of pre-defined "default" payment terms present in your application from the start, these would already be present in the payment terms table. However, I would put a reference table in between USERS and PAYMENT TERMS:
USERS:
user-id
user_namde
USER_PAYMENT_TERMS:
userID
payment_term_id
PAYMENT_TERMS:
payment_term_id
payment_term
Your business layer should offer up to the user (or more likely, the administrator) through a GUI the ability to:
Assign 0 to many payment term options to a particular user (some
users may not want one of the defaults to even be available, for
example.
Add custom payment terms, which then become available for assignment to one or more users (but which avoids the creation of duplicate payment terms by different users)
Allows the definition of a custom payment term to be assigned to more than one user (say the user's company a unique payment process which requires all of their users to utilize a payment term other than one of the defaults? Create the custom term once, and assign to all users.
Your application business layer would establish rules governing access to payment terms, which could then be accessed by your user interface.
Your UI would then (again, likely through an administrator function) allow the set up of one or more payment terms in addition to the standards you describe, and then make them available to one or more users through something like a checked list box (for example).
Option 1 is definately better for the following reasons:-
Correctness
You can implement a database constraint for uniqueness of the payment term name
You can implement a foreign key constraint from Invoice to PaymentTerm
Ease of Use
Conducting queries will be much simplier because you will always join from Invoice to PaymentTerm rather than requiring a more complex join. Most of the time when you select you will not care if it is an inbuilt or custom payment term. The optimizer will have an easier time with a normal join instead of one that depends on another column to decide which table to join.
Easier to display a list of PaymentTerms coming from one table
We use Option 1 in our data-model quite alot.
Part of the problem, as I see it, is that different payment terms lead to different calculations, too. If I were still in the welding supply business, I'd want to add "2% 10 NET 30", which would mean 2% discount if the payment is made in full within 10 days, otherwise, net 30."
Setting that issue aside, I think ownership of the payment terms makes sense. Assume that the table of users (not shown) includes the user "system" as, say, user_id 0.
create table payment_terms (
payment_term_id integer primary key,
payment_term_owner_id integer not null references users (user_id),
payment_term_desc varchar(30) not null unique,
);
insert into payment_terms values (1, 0, 'Net 10');
insert into payment_terms values (2, 0, 'Net 15');
...
insert into payment_terms values (5, 1, '2% 10, Net 30');
This keeps foreign keys simple, and it makes it easy to select payment terms at run time for presentation in the user interface.
Be very careful here. You probably want to store the description, not the ID number, with your invoices. (It's unique; you can set a foreign key reference to it.) If you store only the ID number, updating a user's custom description might subtly corrupt all the data that references it.
For example, let's say that the user created a custom payment term number 5, '2% 10, Net 30'. You store the ID number 5 in your table of invoices. Then the user decides that things will be different starting today, and updates that description to '2% 10, Net 20'. Now on all your past invoices, the arithmetic no longer matches the payment terms.
Your auditor will kill you. Twice.
You'll want to prevent ordinary users from deleting rows owned by the system user. There are several ways to do that.
Use a BEFORE DELETE trigger.
Add another table with foreign key references to the rows owned by the system user.
Restrict all access through stored procedures that prevent deleting system rows.
(And flags are almost never the best idea.)
Applying general rules of database design to the problem at hand:
one table for system payment terms
one table for user payment terms
a view of join of the two above
Now you can join invoice on the view of payment terms.
Benefits:
No flag columns
No nulls
You separate system defaults from user data
Things become straight forward for the db
Data in one table is referenced by ID to another Table. For example, I have a table of States with ids 1-50. In another table "User" I have a reference to that id ie. state= 4. When I need to update data back to "User", if the state changes, should my code be aware of the numbering of the state data? In other words, if the new state is Alabama id=1, i should enumerate before submitting to database? Or should the DataAccess layer search the datatables for theid for the new state?
The specifics of this depend on what your front end is, but in general you should pass around the id as well as the state name, so when the user selects Alabama, id 1 gets pased back to your DAL so it can set StateID in the user table directly to that with no additional selects.
E.g., if the front end is a web page,
<select>
<option value=1>Alabama</option>
...
</select>
You should never need to perform an additional search check in the db, if your database has a proper foreign key on the user table column that references the states primary key column. Having this will always ensure a legit value is persisted to your user record.