SQL server constraint - unique key or index? - sql-server

I have a table that contains all products. There are 3 distinct types of products so these have their own tables, lets say ProductType1, ProductType2, ProductType3.
There is a 1-1 relationship between Products and ProductType(n) on ProductId, but to further constraint the child tables there is an additional relationship using a ProductId, ProductTypeId in Products, and a ProductId, ComputedProductTypeId in each of the other tables.
This ensures that a product can only be added to a single matching ProductType table.
The question is this. As there is already a relationship between the 2 tables on ProductId, rather than using an index for the FK, can I get away with a unique key to constrain the relationship, or will this cause performance issues?
Products
PK ProductId
FK ProductId, ProductTypeId
^
*Add an index for this or unique key constraint?*
ProductType(n)
PK ProductId
FK ProductID, ComputedProductTypeId (fixed int)

Creating an index will be better approach.
If you want to delete entries from your master table, SQL server looks for FK relations if any exists. So Creating Index on your composite key (which includes FK) will speed up the process.

Related

Creating a foreign key against a composite key in MS SQL Server

I'm trying to create a foreign key between two tables. Problem is one of those tables has a composite primary key..
My tables are products (one row per product) and product_price_history (many rows per product).
I have a composite key in product_price_history, which is product id and start date of a specific price for that product.
Here's my code :
CREATE TABLE products (
product_id INT IDENTITY(1,1) PRIMARY KEY,
product_name VARCHAR(50) NOT NULL,
product_desc VARCHAR(255) NULL,
product_group_id INT
)
CREATE TABLE product_price_history (
product_id INT NOT NULL,
start_date DATE NOT NULL,
end_date DATE NULL,
price NUMERIC (6,2) NOT NULL
)
ALTER TABLE product_price_history
ADD CONSTRAINT pk_product_id_start_dt
PRIMARY KEY (product_id,start_date)
Now I'm trying to create a foreign key between the products table and the product_price_history table but I can't because its a composite key.
Also it doesn't make sense to add the start date (the other part of the foreign key) to the products table.
What's the best way to deal with this? Can I create a foreign key between these tables? Do I even NEED a foreign key?
My intentions here are
to enforce uniqueness of the product price information. A product can only have one price at any time.
to link these two tables so there's a logical join between them, and I can show this in a database diagram
The foreign key on the product_price_history table should only include product_id. Your target is to ensure that any entry product_price_history already has "parent" entry in products. That has nothing to do with start_date.
The way I see this situation, in theory, fully normalized version of the tables would have to have current_price as unique value in products table. And the product_price_history is simply a log table.
It's not necessary to do it this way, with a physical field, but thinking from this perspective helps to see where your tables model is slightly de-normalized.
Also, if you make product_price_history table anything but simple log table, how do you ensure that new start_date is newer than previous end_date? You can't even express that as a primary key. What if you edit start_date later? I would even think to create different compaund key for product_price_history table. Perhaps product_id+insert_date or only auto-increment id, while still keeping foreign key relationship to the products.product_id.

View to sum over products

I have three tables for a mock/fake database I am creating to learn SQL
Purchases
PK Purchase_ID
FK Creditcard_ID
Order_Date
Products
PK Product_ID
Product
Description
Cost
Purchases_Products
PK Purchases_Products_ID
FK Purchase_ID
FK Product_ID
Quantity
Review
I want to add a View column under Purchases, Total_Cost, that computes this value:
Summation[Product_ID]_(Purchases_Products.Quantity * Products.Cost)
Which sums over all products belonging to a single Purchase_ID. This will require a join. How may I accomplish this?
(edit: While learning how to use a join in a constraint for a Junction Table to prevent null values in parent tables was a great read and something I may want to implement, I still do not understand my question any better sadly.)

Have a relationship between one table with one primary key and another with two primary keys?

I'm asking about this generally, but I'll give an example for illustration purposes.
Table1 has the following columns:
ID (Pk)
Order_Desc
Order_DT
Table2 has the following columns:
ID (PK)
Product_Code (PK)
Product_Desc
Is it possible for me to have relationship between Table1 and Table2. If so, how would you do this in SQL without you running into an error? Would you be able to create a relationship if the Product Code or ID was not a primary key? Instead, it was a foreign key?
Your table2 does not have two primary keys - it has ONE primary key made up from 2 columns. Any relational table NEVER has more than one primary key - it's just not possible at all.
Any FK relationship to that table must include all the columns that the PK of the referenced table has - so any FK to Table2 must include both ID and Product_Code.
It's an all or nothing proposition - either your foreign key includes all columns of the referenced tables primary key - or you cannot establish a FK-relationship.

Is it ok to have a primary key relate to another primary key?

Here's the part of my ERD:
OrderID from the Orders table relates to the OrderID/ProductID primary key in the Order Details table. I don't think primary keys can relate to other primary keys, but I'm not sure how else to relate the tables. Make them both primary and foreign keys?
You seem to be missing some basic ideas behind PKs (primary keys), UNIQUE NOT NULL, FKs (foreign keys), superkeys, CKs (candidate keys), simple vs composite PKs/UNIQUEs and ERDs (Entity-Relationship Diagrams). From this recent answer:
PKs & FKs are erroneously called "relationships" in some methods and
products. Application relationships are represented by tables. (Base
tables and query results.) PKs & FKs are constraints: they tell the
DBMS that only certain situations can arise, so it can notice when you
make certain errors. They are not relationships, they are statements
true in & of every database state and application situation. You do
not need to know constraints to update and query a
database.
Just declare per what is true of your relationships/tables:
a PK or UNIQUE NOT NULL declaration says that every subrow value in a column set is unique. Ie that the column set is a superkey. (A PK is just a distinguished UNIQUE NOT NULL.)
a FK declaration says that a column list subrow value in referencing columns must also be in referenced superkey columns.
I don't think primary keys can relate to other primary keys,
They can: A primary key can be a FK referencing another superkey. (You seem to be using "relates to" to mean "is referenced by a FK in").
But note: Here you have two PKs Order OrderID & Product ProductID referenced as FKs in ("relating to") OrderLine. But they are each FKs referencing ("relating from"?) part of OrderLine composite PK {OrderID,ProductID}.
but I'm not sure how else to relate the tables.
First declare CKs (candidate keys): Superkeys that don't contain smaller superkeys. Then declare FKs. (Then for a SQL DBMS declare any undeclared superkeys referenced by FKs.)
Make them both primary and foreign keys?
Yes: They are PKs in Order & Product. They are FKs in OrderLine referencing Order & Product. And the PK of OrderLine happens to be {OrderID,ProductID}.
PS In your style of ERD the lines are (apparently) merely FKs, with all the entities and relationships having tables. In some forms of ERDs there are entity tables, labeled lines representing relationships/tables (each end involving a FK) and unlabeled lines representing just FKs. When you see a diagram style always be sure you understand how to determine what icons represent relationships/tables and just what those relationships are in terms of the application. (Not just their cardinalities.)
I don't think primary keys can relate to other primary keys, but I'm
not sure how else to relate the tables.
This is perfectly fine, and it is quite commonly done.
What you are doing is referred to as a Compound Key. Compound keys don't have to link to other tables, but they can.
The relationships indicated by your diagram are not relationships between two primary keys. It looks like the attribute OrderID in Order Details references the Orders table. The attribute ProductID in Order Details references the Products table. These are sometimes called identifying relationships because the referencing attributes happen to be part of a key.
Relationships between keys are perfectly valid but that isn't what is shown in your diagram.
What is shown on the diagram is a FK relationship and is common
Orders and Products have PK so OrderID and ProductID are unique
So now you have OrderDetails so an order can have multiple products
The FKs assure valid values for OrderID and ProductID
In addition you should add a composite PK of OrderID, ProductID on OrderDetails
This way you don't have duplicate ProductID for the same OrderID
You have Quantity for dealing with multiple
UnitPrice is a catch
If you want to have multiple unit price for a ProductID in an OrderID then you would not be able to declare OrderID, ProductID as a PK
I would avoid going down that path if you can
Some of the answers conflate the concepts of relationships and foreign key constraints, as do many (most?) ER diagramming tools.
For clarification, there are 6 relationships (in the sense that Chen used the word) visible in the diagram:
Orders.OrderID, Orders.CustomerID
Orders.OrderID, Orders.ShipperID
Orders.OrderID, Orders.PaymentTypeID
OrderDetails.OrderID, OrderDetails.ProductID
Products.ProductID, Products.ProductTypeID
Products.ProductID, Products.LocationID
and 7 foreign key constraints (I assumed some table names):
OrderDetails.OrderID ⊆ Orders.OrderID
OrderDetails.ProductID ⊆ Products.ProductID
Orders.CustomerID ⊆ Customers.CustomerID
Orders.ShipperID ⊆ Shippers.ShipperID
Orders.PaymentTypeID ⊆ PaymentTypes.PaymentTypeID
Products.ProductTypeID ⊆ ProductTypes.ProductTypeID
Products.LocationID ⊆ Locations.LocationID
They aren't the same thing at all.

SQL Server table PK and FK

I am creating a relationship between 2 tables:
The relationship I like to form is between the Inventory an InventoryExtended tables.
The primary key for the Inventory table is InvID (Inventory ID).
The reason why I created the InventoryExtended is becauses only 1% of the inventory items in the Inventory table will need additional or extended fields, the rest will not.
Instead of adding these additional fields in the Inventory table where 99% will be blank for 50 additional fields that I need I decided to create an InventoryExtended table and store the 50 fields there.
The relationship between the Inventory an InventoryExtended table will be 1 to 1.
Meaning, for the 1% of the records in the Inventory table , the InvId will be the same as the InvId in the InventoryExtended table.
My question is that should the InvID in the InventoryExtended table be a FK (Foreign Key) or should it be a PK and a FK?
I am thinking it should be a PK and a FK as there the InvID will be unique in the InventoryExtended table.
Thanks in advance.
You are correct.
The InvID should be a PRIMARY KEY and a FOREIGN KEY as it will be unique in the InventoryExtended table.
This type of relationship is indeed 1:1 or (more accurately) 1::0..1, as only some of the rows in the Inventory table will have a related row in InventoryExtended.
Also note that the InventoryExtended (InvID) should not have the IDENTITY property, even if the Inventory (InvID) has it.
The InvID will be both a PK and FK for the extended table.
If you know in advance (meaning when you attempt to fetch data) whether or not a particular inventory type will have the extended data, for such records you can even skip the original table altogether and simply use two disjoint tables smallInventory and bigInventory such that no records of one are present in the other.

Resources