Indirect UNIQUE constraint - sql

I've had a following set of tables:
CREATE TABLE sellers (
id integer PRIMARY KEY,
....
);
CREATE TABLE buyers (
id integer PRIMARY KEY,
....
);
CREATE TABLE invoices (
id integer PRIMARY KEY,
number varchar(40),
buyer_id integer REFERENCES buyers(id),
seller_id integer REFERENCES sellers(id),
UNIQUE(seller_id, number),
....
);
The UNIQUE constraint is enforces the constraint that one seller can have only one invoice with given number.
I wanted to create a new table, mostly as a many-to-many relationship between buyers and sellers:
CREATE TABLE suppliers (
id integer PRIMARY KEY,
buyer_id integer REFERENCES buyers(id),
seller_id integer REFERENCES sellers(id),
....
);
As a normalization effort, i would like to change invoices to refer to suppliers, like this:
CREATE TABLE invoices (
id integer PRIMARY KEY,
number varchar(40),
supplier_id integer REFERENCES suppliers(id),
....
);
My question is: how can I replace the UNIQUE constraint?

Use a composite primary key for suppliers:
CREATE TABLE suppliers (
buyer_id integer REFERENCES buyers(id),
seller_id integer REFERENCES sellers(id),
...
PRIMARY KEY (buyer_id, seller_id),
...
);
and keep your invoices table intact, only changing the two foreign keys into one:
CREATE TABLE invoices (
id integer PRIMARY KEY,
number varchar(40),
buyer_id integer,
seller_id integer,
UNIQUE (seller_id, number),
FOREIGN KEY (buyer_id, seller_id)
REFERENCES suppliers (buyer_id, seller_id),
....
);
I guess that this design will be useful, if you plan to have more columns in the suppliers table that are related to the seller - buyer relationship. Otherwise, you could have a view that gathers data from the invoices table:
CREATE VIEW suppliers AS
SELECT DISTINCT buyer_id, seller_id
FROM invoices ;

Related

How to connect two fact tables to one dimensional table

I have two fact tables (HistoricTable, ForecastTable). Both tables use a composite key that combines the productID and WeekID together. The ForecastTable has future weekID's & historic has previous ones. I want both of these ProductID's to reference one Dimensional table called ProductTable. How do I connect them?
My assumption would be to create an additional table that queries HistoricTable & ForecastTable via UNION join and have that connected to the ProductTable. Is this logic correct?
Table Image Layout
I want both of these ProductID's to reference one Dimensional table called ProductTable.
You can establish one foreign key between historic and product and another foreign key between forecast and product.
For example:
create table product (
id int primary key not null,
name varchar(10)
);
create table historic (
product_id int not null references product (id),
week_id int not null,
units_sold int,
primary key (product_id, week_id)
);
create table forecast (
product_id int not null references product (id),
week_id int not null,
forecast_units int,
primary key (product_id, week_id)
);

Is it possible to reference a foreign key to parent table?

CREATE TABLE Product
(
"Product_id" int,
"Stock_quantity" int,
"Product_name" varchar(50),
"Model" varchar(50),
"Average_rating" float(3),
"RAM" int,
"Color" varchar(20),
"Price" float(10),
PRIMARY KEY ("Product_id")
);
CREATE TABLE Sale
(
"Sale_id" int,
"Sale_date" date,
"Employee_id" int,
"Customer_id" int,
"Product_id" int,
"Product_quantity" int,
"Rating" int,
PRIMARY KEY ("Sale_id"),
FOREIGN KEY("Employee_id") REFERENCES Employee("Employee_id") ,
FOREIGN KEY("Customer_id") REFERENCES Customer("Customer_id") ,
FOREIGN KEY("Product_id") REFERENCES Product("Product_id")
);
CREATE TABLE Computer
(
"Type" varchar(10),
"Processor" varchar(20),
"Monitor_size" int
) inherits(Product);
CREATE TABLE Mobile
(
"Os" varchar(30),
"Screen_size" int
) inherits(Product);
Here is my tables while insertion of sale rows I get this error.
ERROR: insert or update on table "sale" violates foreign key constraint "PK_Product_id"
SQL state: 23503
Detail: Key (Product_id)=(12) is not present in table "product".
It says there is no presence of the row, but I can see them when I view the table:
I inserted every product as computer or mobile not as product.
You are stumbling over one of the many quirks with inheritance: There are no “global” constraints on an inheritance hierarchy, consequently you cannot have a foreign key to a inheritance hierarchy.
The primary key you defined on product does not extend to computer.
Even though a SELECT on product will append the results for the inheritance children as well, these are not part of the table parent and consequently cannot be used as target for the foreign key. The foreign key is between sale and product only, the inheritance children are excluded.
There is no proper way to do this with inheritance.
It is better for computer not to be an inheritance child of product, but to have a foreign key to product (with a unique constraint on it), so that the data for a computer object will be split between the two tables. This is somewhat inconvenient for queries, but you can have a foreign key that way.
Here is an example:
CREATE TABLE product (
product_id integer PRIMARY KEY,
prodname text NOT NULL
);
CREATE TABLE computer (
product_id integer PRIMARY KEY,
processor text NOT NULL,
FOREIGN KEY (product_id) REFERENCES product(product_id)
);
CREATE TABLE sale (
sale_id integer PRIMARY KEY,
product_id integer NOT NULL REFERENCES product(product_id)
);
Now there is no direct foreign key reference from sale to computer, but since the product_id of computer and product is identical, you can always find the unique computer for a sale if it exists:
SELECT p.prodname, c.processor
FROM sale s
JOIN product p USING (product_id)
LEFT JOIN computer c USING (product_id)
WHERE sale_id = 42;
If you have more product “subtypes”, you can add more left joins.

oracle - how to use foreign key constraints in object types

I have an error in the last line in Create table and i dont know how to use foreing key correctly.
CREATE TYPE CarType AS OBJECT(
price_id NUMBER,
quantity NUMBER
);
CREATE TABLE Cars(
carid NUMBER PRIMARY KEY,
carinfo CarType,
CONSTRAINT car_fk FOREIGN KEY(price_id) REFERENCES Prices(price_id)
);
CREATE TYPE CarType AS OBJECT(
price_id NUMBER,
quantity NUMBER
);
create table Prices
( cType CarType,
constraint pk_prices primary key (ctype.price_id) );
CREATE TABLE Cars(
carid NUMBER PRIMARY KEY,
carinfo cartype,
CONSTRAINT car_fk FOREIGN KEY(carinfo.price_id) REFERENCES prices(cType.price_id)
);
I assumed that you have Prices table that you didn't include in your question.

What is the best way to enforce constraints across tables?

I often find myself running into situations like this one (which is contrived but illustrative of the problem):
CREATE TABLE customer (
id SERIAL PRIMARY KEY,
type TEXT
-- other columns...
);
CREATE TABLE product_order (
id SERIAL PRIMARY KEY,
customer_id INTEGER REFERENCES customer (id),
type TEXT REFERENCES customer (type), -- not actually legitimate
-- other columns...
CHECK (type = 'business')
);
Of course, the foreign key constraint on product_order.type doesn't work because customer.type is not UNIQUE or a primary key (and I can't use a CHECK CONSTRAINT on a column that only exists in another table). However, I would only like product_order entries for type = 'business' customers.
I could make customer.id and customer.type a composite primary key, but then any other tables that want to reference just customer.id must also reference customer.type unnecessarily.
What's the best approach in this situation?
EDIT: Forgot the foreign key constraint product_order.customer_id!
If you create a unique constraint on the customer.type you can reference it from the product_order table:
CREATE TABLE customer (
id SERIAL PRIMARY KEY,
type TEXT,
-- other columns...
constraint unique_cust_type unique (id, type) -- this makes the combination id/type "referencable"
);
CREATE TABLE product_order
(
id SERIAL PRIMARY KEY,
customer_id INTEGER,
type TEXT default 'business',
CHECK (type = 'business'),
foreign key (customer_id, type) references customer (id, type)
);
You could make a lookup table for types, and use the FKEY relationship to enforce
CREATE TABLE type (
id integer, PRIMARY KEY,
name TEXT
);
CREATE TABLE customer (
id SERIAL PRIMARY KEY,
type_id INTEGER, NOT NULL
-- other columns...
FOREIGN KEY (type_id) REFERENCES type(id)
);
CREATE TABLE product_order (
id SERIAL PRIMARY KEY,
type_id INTEGER, NOT NULL
-- other columns...
FOREIGN KEY (type_id) REFERENCES type(id)
);
You could access product_order as a view:
create view product_order_vw
as
select po.*
from product_order po
join customer c
on c.customerid = po.customerid
where c.type = 'business'
I think you need another type for the type. This sample is in MS SQL format:
CREATE TABLE TYPES (ctype varchar(10) NOT NULL PRIMARY KEY,
name varchar(50) not null
);
CREATE TABLE product_order (
id SERIAL PRIMARY KEY,
type varchar(10) NOT NULL REFERENCE TYPES (ctype) ,
....
);
So your product_order must have types defined in Types table. In your sample, you have only one entry 'business' but you can add as many as you want.

Deleting related rows from other tables without primary key

I need to delete the associated rows from the "assign" table when a crew member is deleted.
However, when I create the tables, I get the error:
ERROR: there is no unique constraint matching given keys for referenced table "assign"
It seems as though I need distinct values in the "assign" table, but the whole point is that I want to delete all associated information when a crew member is removed. How can I do this?
create table flight(
flight_num BIGSERIAL PRIMARY KEY,
source_city varchar,
dest_city varchar,
dep_time int,
arr_time int,
airfare int,
mileage int
);
create table crew (
id BIGSERIAL PRIMARY KEY,
name varchar,
salary int,
position varchar,
seniority int,
fly_hours int,
mgrid int,
FOREIGN KEY (id) REFERENCES assign(id) ON DELETE CASCADE
);
create table assign (
id int, # refers to a crew member id, not a row id
flight_num int
);
The foreign keys should be on the M-M join table, as so:
create table flight(
flight_num int PRIMARY KEY,
-- etc
);
create table crew (
crew_id int PRIMARY KEY,
-- etc
);
create table assign (
crew_id int,
flight_num int,
-- If the corresponding record in either of these FKs is deleted then
-- this record will be deleted.
FOREIGN KEY (crew_id) REFERENCES crew(crew_id) ON DELETE CASCADE,
FOREIGN KEY (flight_num) REFERENCES flight(flight_num) ON DELETE CASCADE,
-- M-M usually should have a PK over both foreign columns, arranged in order
-- of expected usage. A reverse covering index can be added if needed.
PRIMARY KEY (flight_num, crew_id)
);
In this case the FKs are allowed because they are over a unique columns (PKs of crew and flight). The original error is because there was no unique contraint on the FK target (assign.crew_id).