Create the following tables:
Customer
KNr (primary key)
Name (at most 15 characters)
City (at most 10 characters)
Country (at most 10 characters)
Balance (Type FLOAT)
Discount (Type FLOAT)
Products
PNr (greater than 1 and primary key)
Descr (not NULL, at most 10 characters and unique)
Weight (Type FLOAT)
Think about the integrity constraints for the columns Price, StorageLocation and Stock.
Orders
OrdNr (Type INTEGER, greater than 0 and primary key)
Mon (Type INTEGER, not NULL and between 1 and 12)
Day (Type INTEGER, not NULL and between 1 and 31)
PNr (Foreign Key)
KNr (Foreign Key)
The attributes Month, Day, Pnr and Knr must together be unique. Think about the integrity constraints for the columns Quantity, Sum and Status.
I have done the following :
For 1 :
CREATE TABLE Customer
(
KNr PRIMARY KEY,
Name CHAR(15),
City CHAR(10)
Country CHAR(10)
Balance FLOAT
Discount FLOAT
);
Is that correct?
For 2 :
CREATE TABLE Products
(
PNr PRIMARY KEY CHECK (PNr > 1) ,
Descr NOT NULL CHAR(10) UNIQUE.
Weight FLOAT
Price FLOAT CHECK (Price > 0) // Is checking if it is positive an integrity constraint?
StorageLocation CHAR(15) // What integrity constraint do we use here? If it is not Null for example?
Stock INTEGER // What integrity constraint do we use here? If it is not negative for example?
);
Is that correct?
For 3 :
CREATE TABLE Orders
(
BestNr INTEGER PRIMARY KEY CHECK (BestNr > 0) ,
Mon INTEGER NOT NULL CHECK(Mon >= 1 and Mon <=12)
Day INTEGER NOT NULL CHECK(Day >= 1 and Day <=31)
FOREIGN KEY (PNr) REFERENCES Customer (PNr),
FOREIGN KEY (KNr) REFERENCES Products (KNr)
Quantity INTEGER CHECK(Quantity >0) // It is the ordered quantity, or not? What integrity constraints can we consider?
Sum FLOAT // Is this the sum of invoices? Or what is this meant? What integrity constraints can we consider?
Status CHAR(20) // It is meant if is paid, delivered, etc? So this contains words, right? What integrity constraints can we consider?
UNIQUE (Mon, Day, Pnr, Knr)
);
Do we write that as in the last line that the attributes Month, Day, Pnr and Knr must together be unique ?
You are actually pretty close if viewed as logical model defining requirements. From a physical model however, the syntax is considerable off.
I will not do each table but just Orders, and I will slice and dice along the way, leaving some things you need to correct and some suggestions for your considerations.
First off If you want comment on your ddl you can do so, but they begin with -- instead of //. A better approach just use Comment On where they become part of the permanent record.
As a column name nothing wrong but is it clear what BestNr refers to, and what makes it better than any other number. Perhaps a better name would be Ord_nr. (But the is of course just an opinion). Declaring it as Primary comes with 2 automatic constraints: Not Null and Unique. Check constraint again there is nothing wrong. However a better process would be just tell the DBMS to generate identity column (see Create table ... generated ...).
Technically nothing wrong. However there is a data integrity hole as it still permits invalid date. The date Feb 30 would pass both your constraints. But it is still an invalid date. Other months have the same issue, day = 31 for a month with only 30 days passes the constraints but remains invalid. To ensure only valid dates just define a date column. This also eliminates the need for the check constraint. The month and date can be extracted when needed.
Your reference is backwards. PNr refers to Product, KNr to customer. However you must define them as columns then generate the FK. While nothing is wrong with these as columns names, are the descriptive of what they refer to. PNr perhaps, but not so KNr (unless Customer is always referred to as K...) Perhaps better prod_nr and cust_nr. (but perhaps no product reference at all - later).
This column can easily be derived when needed, and will be difficult to keep current (what happens when another item is added to the Order, or Updated, or Deleted). Further this is a very poor choice for a column name as it is a SQL Standard
reserved word (not by all RDBMS however, Postgres being one). Drop the column and derive it when needed.
You would want to constrain this to a set of predefined values. Either a CHECK constraint, an ENUM or a lookup (reference) table.
Consider normalizing a bit further. An order typically will contain multiple items (lines). These can/should be extracted into another table; call it Order_Lines and move PNr and Quantity into it.
Taking all the above into consideration arrive at:
-- method to constrain status
create type order_status as enum ('pending', 'picked', 'shipped', 'delivered', 'billed', 'paid', 'back ordered', 'on hold', 'canceled' ); -- or others
create table orders ( ord_nr integer generated always as identity primary key
, ord_dt date
, cust_nr integer references customers (cust_nr)
, status order_status -- questionable: Can it be derived?
, constraint one_per_cust_per_day unique (cust_nr, ord_dt) -- combine multiple orders for customer into 1 per day. ??
);
create table order_lines ( ord_ln_nr integer generated always as identity primary key -- optional
, ord_nr integer not null references orders(ord_nr)
, prod_nr integer not null references products(prod_nr)
, quantity integer not null check (quantity>0)
, price float -- Note1
, status order_status
, constraint one_ln_per_ord_prod unique ( ord_nr, prod_nr)
);
Note1: Normally do not copy columns from referenced tables. You normally avoid this as it creates duplicate data, just get the value through the reference. However, price
tends to be a volatile column. If a price change occurs, we should not automatically apply that to existing orders. For this reason the Price from the Product will be copied when order is placed.