Naming tables to show association with another table [closed] - sql

Closed. This question is opinion-based. It is not currently accepting answers.
Want to improve this question? Update the question so it can be answered with facts and citations by editing this post.
Closed 9 years ago.
Improve this question
I have a table called Order which holds customer orders.
I want people to be able to add notes to orders. Whats the best way to name this new table? Because other tables may also have notes e.g. Customer, I need the table to be named so that is shows association with the relevant table. Relationship is an Order will have 0-or-many Notes.
So should I name it:
Order_Note
OrderNote
They all seem fine. I also need to create another table that will list the 'types' of Order that have been placed. An Order can have 1 or many 'types'. So how would I name this association in the table name?
Order_Type
OrderType
In this Order_Type table, it will have just two columns OrderID and TypeID. So I need a final table which holds all possible Types of order that can be placed. How do I name this, given that it will be confusing with the table above?
Order_Types
OrderTypes
But this is breaking the rule of not having plurals in table names.
Edit:
The Order table is a data table. Order_Type is a joining table. And finally, OrderTypes is a lookup table. Thanks to Hogan for making this obvious to me. I have also removed hyphenation between words as an option as it may cause future problems.
SOLUTION 1:
Name association between tables using underscore e.g. Order_Type
Name lookup and data tables without underscores e.g. Order, OrderType
I'll also use a schema so that lookup tables show like Lookup.OrderType which helps to clarify what is what.

The way I've done it is listed below
As a side note, these suggestions have to do with how to think about
joined table names and it does not matter if you use camel case or
not, underscores or not etc.
The important note here is that there is fundamentally a difference
between a joining table, a lookup table and a data table. The names
should reflect this and be consistent.
1)
I would make a note table and call it Note. Then I would add a relationship between orders and notes and call it order2note or orderNote or orderNoteRel
This table name defines the two joined tables in some order, sometimes you can put the non-FK first but in many cases it is best to just default to alphabetical.
2)
For tables that define a code (or a type as you put it) I will make a convention of ending the "Type" or "Code" or "CD" etc in the table name.
so orderType or orderCD or orderCode would be for the table that defines order types.
3)
The final table is actually a join between order table and orderType table so it would be
order2orderType or orderOrderCD or orderOrderCodeRel
(or some other combination of the conventions I've shown.)
This is the important one. If you remember that the table you are joining to should have order in its name (it is the orderType table) Then the join between order and order type should have order twice in its name. While this seems redundant at first once you get used to it it makes total sense.

Related

What are some of the best practices for tracking updates to a record over time in sql? [closed]

Closed. This question is opinion-based. It is not currently accepting answers.
Want to improve this question? Update the question so it can be answered with facts and citations by editing this post.
Closed 4 years ago.
Improve this question
I have a product table with a primary key #productid (bigint), a product number (int), and a version (int)
Any time someone makes changes to the product record ONLY, I plan on inserting a new row in the database with the same product number and version number + 1. This will provide me with the historical tracking I need for the record because I can see the version changes throughout time.
/* Selecting the current version is simple */
Select top 1 *
from products
where productnumber = #productnumber
order by version desc
However, my problem comes in with the Foreign key one-to-many or many-to-many relationship tables. This table points to many others (i.e. product pricing with date ranges, product categories, etc.) which also need to be tracked.
/* Product categories, pricing */
/* Should I use #productnumber here? How do I track changes to these records? */
select name
from productcategories
where productid = #productid
select price
from productpricing
where productid = #productid and
StartDate > #StartDate and
EndDate <#Enddate
So now any time there is a version change, I plan to to re-insert new category and pricing records with the new Primary Key product id that was generated..This is going to lead to a ton of duplicates, especially if no changes were made to these records.
Also the issue comes in with - what happens if a category is removed but there were no changes to the product record? I would want to see who removed the category. Essentially, a full audit is needed on each table.
I have seen some different examples but most of them only seem to deal with a record in one table and not a record that is a part of one-to-many or many-to-many relationships. I was hoping this could be done without the need of additional tables.
Are there any better methods or practices? Is this going to be a performance nightmare?
If you are using a newer version of SQL Server as you are, you can should look into temporal tables as this might be your best option.
If you need to support older versions, my preferred method is to have a history table with a new PK column, change flag (I,U,D), a date modified, user that made the change, and all of the columns from the primary table. I then index the column related to the PK of the non-history table. Triggers don't impact performance too much if you don't put logic in them.
Example (pseudocode):
Table: Car
Column: CarID INT IDENTITY(1,1) Primary Key
Column: Name varchar
Table: Car_hist
Column: Car_histID INT IDENTITY(1,1) Primary Key
Column: Change char(1)
Column: DateOfChange DateTime2
Column: ChangedByUser (varchar or int)
Column: CarID <-add a unique non-clustered index
Column: Name varchar
You can write a generator in SQL that generates the script to create the history table, indexes, etc. It helps if you have a consistent table design practice.
Now the reason: I rarely have to query history tables, but when I do, it is almost always for a single record to see what happened and who changed it. This method allows you to select from the history on the parent table's PK value quickly and read it as a historical change log easily (who changed what and when). I don't see how you can do that in your design. If you are really slick, you can find or write a grid that diffs rows for you and you can quickly see what changed.

Is storing calculated values in database a bad idea? [closed]

Closed. This question needs details or clarity. It is not currently accepting answers.
Want to improve this question? Add details and clarify the problem by editing this post.
Closed 2 years ago.
Improve this question
Let's say I'm working on an online store project. So, I'm gonna have to create a table called 'Product' in my database. Say I also want users to be able to 'like' my products. That requires me to create another table called 'ProductLike' to store users' IDs alongside the ID of the product they like (a junction table).
The main scenario: Every time when a user sends a request to my website to get a product page, I'm gonna have to recalculate the number of likes that product has.
My question is: So, I know the standard approach is not to store 'Calculated values' in the database (normalization). But what about cases like this? (I mean cases in which it might be expensive to calculate something). For instance in the example above, isn't it better to have a column named 'NumberOfLikes' in the 'Product' table to store the calculated number of the product likes for fast retrieval?
Update
isn't it better to have a column named 'NumberOfLikes' in the 'Product' table to store the calculated number of the product likes?
IMHO, the direct answer to this question is "No, unless you have a real performance problem due to the counting of likes".
If you do have a performance problem, and you've identified its source as the count of likes, Then you might want to consider adding a LikesCount column to the products table. If you do add such a column, please note you are going to have to update it on every change to the ProductLike table - delete, update and insert.
This means you are going to have to write a trigger for this table to handle all these cases, but it shouldn't be too hard since you can do everything in a single trigger - something like this:
create trigger ProductLikeChaneged on ProductLike
for insert, update, delete
as
update p
set LikesCount = (select count(*) from ProductLike as pl where pl.productId = p.Id)
from product as p
where exists
(
select 1 from inserted as i where p.id = i.productId
)
or exists
(
select 1 from deleted as d where p.id = d.productId
)
Original version
Based on your description, "calculating" the number of likes for a product is simply a count of rows in the ProductLike table where the product id is the id of the product you are currently displaying to the user.
This can be done very fast, especially if the ProductLike table clustered index is ProductId and then UserId, thus allowing SQL Server to use clustered index seek and not a table scan.
Basically, your ProductLike table should look like this:
Create table ProductLike
(
ProductId int,
UserId int,
Constraint PK_ProductLike PRIMARY KEY (ProductId, UserId)
)
Note that by default, SQL Server will use the primary key as the clustered index of the table.
Then your select statement for the product page can be something like this:
select Name, Description, -- Other product related details
(select count(*)
from productLike as pl
where pl.ProductId = p.Id) as likeCount
from product as p
By "calculated" value, I suspect you mean an accumulation of the number of requests.
The simplest approach in terms of database design and maintenance is to store each request as a row in a table and to summarize when needed. This has certain nice features:
A user can "unrequest" or "unlike" quite easily.
Inserts are (typically) at the "end" of the table, minimizing fragmentation and speeding inserts. Note: This can result in contention for the last page if multiple threads are writing at the same time.
Counts can be flexible, limited to a particular date range or type of user for instance.
The data is drill-downable. That is, for a given count you know exactly what produced it.
Summarization is often very reasonable, if you have the right indexes and partitions on the data.
That said, such summarization does not meet all needs. A traditional approach is to use a trigger to maintain summary tables -- adding lots of complexity for maintenance (you need insert, delete, and update triggers). I think #daniherrera's answer gives guidance on the best approach.
For real life they are real solutions. You should to materialize this field and denormalize database to keep performance. Do you have serveral options to keep this field uptodate:
Materialized views.
Triggers.
Store procedure.
Disclaimer: Your question is a primary opinion-based, I guess will be closed in a while.
Number of product liked by user can be fetched by UserProductLike table, where userid is id of your user.

SQL Select Sub Query [closed]

Closed. This question is opinion-based. It is not currently accepting answers.
Want to improve this question? Update the question so it can be answered with facts and citations by editing this post.
Closed 5 years ago.
Improve this question
I have the following database tables
User List
------ ------
userId (PK) listId (PK)
fullName description
addedById (FK with userId in User table)
modifiedById (FK with userId in User table)
I need to pull out all data from the List table, but instead of showing the IDs for addedById and modifiedById, I need to pull the fullName from the User table.
This query works, and gives me the data I need. However, I'm not sure if there is a better way of constructing this query? I'm not keen on having multiple sub select queries within my main select query, mainly because of performance issues.
select t1.[description],
t1.addedById,
t1.modifiedById,
(select fullName from dbo.User where userId = t1.addedById) as [AddedByUser],
(select fullName from dbo.User where userId = t1.modifiedById) as [ModifiedByUser]
from dbo.List t1
I'd really appreciate if anyone could suggest improvements to the query, or advise to keep as is.
Thanks.
A more standard SQL method would be:
SELECT t1.description,
t1.addedById,
t1.modifiedById,
add.fullName AS [AddedByUser],
mod.fullName AS [ModifiedByUser]
FROM dbo.List t1
LEFT JOIN dbo.User add
ON add.userId = t1.addedById
LEFT JOIN dbo.User mod
ON mod.userID = t1.modifiedById
However, I suspect this will perform identically to your query and probably has an identical execution plan. The only real advantage to this method is that it's easier to expand. For example, if you wanted to add new columns from the User table this would be easier.
As #Gordon notes, performance should be fine if there's an index on the fields you're joining with.
Is that double join with same table bothering you? It's not slow, its preferred way of doing it instead making the linked subquery.
I am assuming you got indexes on PK and both FK.
Only thing you can minimize is to lessen the number of joined rows. You can do that
by either using the left inner join or filtering in the end with where clause stating both keys you use in join must be not null
I can write both examples for you but this should be self explanatory.
Other mayor thing you can do is to PRESELECT values from users. For example if you have a shit ton of users, and you know only few of them can be in either role. And you can filter which ones by some column in Users you haven't listed, even better if that column has an index.
Then you can maybe profit from pre-selecting only those users and then joining to selection result. Either by temp table if both can be pre-selected or by making a select on spot instead joining to the entire table. Not sure about numbers we are dealing with here for this to become relevant..

Which ERD is more correct re proper Database Design? [closed]

Closed. This question is opinion-based. It is not currently accepting answers.
Want to improve this question? Update the question so it can be answered with facts and citations by editing this post.
Closed 9 years ago.
Improve this question
Which ERD is more correct re proper Database Design?
ERD #1
or
ERD #2
Please explain why one is more correct than the other.
ERD 1 Author: Ben Grunfeld
ERD 2 Author: Darren Frenkel
In my opinion ERD #1 is a better design.
Reasons
Orders/Product Table will have OrderID for a particular Order and for each Product Orderd and
quantity for that product for each Order. no repetition/No redundant data.
ERD #2
Is a poor design as each order can have multiple products and you will
be adding the same orderid, CustomerID, Invoicedetails for multiple
products for the same Order, in simple words more redundant data.
Edit
ERD #2 also violates the database normalization rules. In orders Table
you have InvoiceID and then Invoice_Creation_Date which only depends
on the InvoiceID .
normalization rules say if a column in a table doesnt directly depend
on the Primary Key in that column it should be in a separate table. In
other words all the columns in a table should Directly depends on
Primary key only.
In ERD 1 you can only have one item per order -- hence the need for a join table in ERD2
ERD2 - Why would you have a FK in the invoice table for order_ID, and also have invoice_ID in the order table. One FK field is enough. I assume this is a one order to many invoices, in which case you would put the order_ID in the invoice table
ERD2 is written incorrectly the foreign key Order_ID_FK should be removed from Invoices. Therefore, Invoices should have a one to many relationship with Orders.

Commonly concepts in adding contacts for staffs using master table [closed]

Closed. This question is opinion-based. It is not currently accepting answers.
Want to improve this question? Update the question so it can be answered with facts and citations by editing this post.
Closed 9 years ago.
Improve this question
Using MS SQL: The scenario is I have already a Contact master table (tbl_Customer)for all contacts in the company. The staffs suggested that they do not want to see all the contact and that they will only choose which contacts are applicable for them. The contact table is not gonna be store on the client like an outlook's pst file but on server side particularly on the database.
The methods i can use are:
1.) every time i add a staff i create a new independent table for the staff and the staff just adds the contact he/she needs from the master table via a program.
2.) I can change the contact master table to add say 50 fields with names staff01, staff02 and so on... I will make use of this fields as a marker that this rows of customer is a contact of the staff on the fields.
3.) I do a completely new contact list. Adds a field name "User". Mark the initial records via putting "ALL" on the field name. If a staff adds a contact, the table add a record with his/her name on the field "User". There will be an Auto numbered field as primary index.
Currently I'm tempted to use 3.) are there any other better method for my problem?
Why don't you have a staff table with a staff id - then every contact the staff in question wants can be a row in staffContacts. Column 1 is staffID and col 2 is contactID. Then you can join on the contact table to retrieve the details you want.
The contacts table then only needs be updated...You only need to add one table with two columns. You may wish to impose constraints that let fields be entered that are unique to staffID and contact ID and are valid staff members and contacts.
Nick.
If I understand correctly you want to have a list of the contacts that is filtered specifically based on a particular users preferences?
Personally I would create another table like this:
Create Table UserContactPreferences
(
ID int identity(1,1),
UserID int,
ContactID int,
)
And then each individual user can pick what contacts they want visible and you can add an entry here for it.
Then when you query the database you can do something like this, passing in the CurrentUser in the query:
SELECT c.*
FROM tbl_Customer c
JOIN UserContactPreferences up on c.contactID = up.contactID
WHERE up.UserID = #CurrentUser
This will then only return Customers that the user has specifically said they want to see.
In case many staff members have the same relevant contact - you should use a connection table, in which there will be 2 columns - one with the contact id , and one with the staff member id, use this table to query for staff's relevant contacts.
In case each contact has only one staff, than simply add a column with the relevant staff id, which will be a foreign key to the staff's table.
In any case and for other users to learn from:
method 1 you suggested is a big no no in SQL DB design, you need a really good reason for a DB with dynamically created tables.
method 2 is bad practice since most of the space will be wasted (unless defined as sparse columns but even though.. still space consuming) and also too specific - what will happen when you add a new staff member ? add a new column ? lock the whole DB for it and add many wasted space allocated?