valid schema for company and suppliers and clients? - sql

I am having a problem in modeling relation between a company and suppliers and clients. Basically in my system the supplier and the client are companies too so I made this schema:
table.company:
id
name
//other fields
table.company_suppliers:
company_id FK table.company.id
supplier_id FK table.company.id
table.company_clients:
company_id FK table.company.id
client_id FK table.company.id
Is this ok?

I would use only one table which will contains all the company and a bit field (called by instance Supplier )which will tell you which are are suppliers too.
Company
Id
Name
IsSupplier (bit)
Fk_IdSupplier --it will relate this supplier to a company on the same table
Or you can create a junction table (many to many)
Company
Id
Name
IsSupplier (bit)
CompanySupplier
fk_IdCompany
fk_IdSupplier

Your basic insight is right--you don't want unrelated tables of clients and suppliers. But you have too many ID numbers.
create table companies (
company_id integer primary key,
company_name varchar(35) not null
);
create table suppliers (
supplier_id integer primary key references companies (company_id)
-- Other supplier columns go here.
);
create table clients (
client_id integer primary key references companies (company_id)
-- Other client columns go here.
);
If you're using MySQL, you'll need to adjust the syntax a little. MySQL doesn't support all the standard SQL syntax for declaring primary keys and foreign keys.

Related

How to create an SQL column that can have multiple values?

I created a table in SQL using PostgreSQL called "tenants". Below is the code for the tenants:
create table tentants (
id bigserial not null primary key,
tenant_name varchar(1000) not null,
offices int not null,
number int not null,
email varchar(1000)
I want to include the ability to add multiple values to "office" in case a tenant rents more than one office. I don't want to use JSON for this. I tried creating a related table called "offices" but That could only allow me to add one office per tenant.
What is the best approach for this?
You can use text, that works for me with ids separated by commas like this
4,3,67,2
Anyway the proper approach would be another table and name it tenant_offices
tenant_offices
columns >
tenant_id
office_id (well ofcourse you should have atleast an office table)
You can create an "tenant_offices" table (like you did before), having as structure :
id, tenant_id, office_id,... where id is the primary key of the "tenant_offices" table and tenant_id and office_id are foreign keys.
tenant_id which refers to your tenants table and office_id which refers to your offices table.
Here, the tenant can therefore rent several offices.
Hoping to have enlightened you, or helped !
I assume that the relationship is one-to-many tenant to office (that is, office can be rented only by one tenant)
Then you have to create table offices with a foreign key that points to the tenant:
CREATE TABLE offices (
id bigserial not null primary key,
tenant_id bigserial foreign key references tenants(id))
additional columns if needed
note that in this version you will not retain history of rents (you will have to run update on offices to change tenant_id)
EDIT: In case of a many-to-many relationship (that will also allow us to retain history of rents) we need to create a relationship table:
CREATE TABLE TenantsOffices (
id bigserial not null primary key
tenant_id bigserial foreign key references tenants(id),
office_id bigserial foreign key references offices(id),
start_date datetime,
end_date datetime)
Useful information: https://www.sqlshack.com/learn-sql-types-of-relations/

Order management SQL schema

I am designing a SQL database for sales person of a firm, where each customer will order multiple items from the firm. I want to store this order uniquely to the customer. Which will be linked to customer table.
Customer Table :
Cust_id
Cust_name
Cust_phone
Currently I am thinking of making a separate order table for each order
Order Table:
Product_id
Prod_quantity
Total_amt
but can't figure out how to link it back to customer. Or how to uniquely identify each order table.
I would have done it in NoSQL but data has to be locally stored in SQLite.
Customer may order multiple times so I should be able to identify current and previous orders
Do not create a separate table for each order! That's a very bad design. Relational tables aren't spreadsheets!
Have one table for the orders with a foreign key pointing to the customers. For the items of orders have a linking table with a foreign key to the order and another to the item. That's fairly standard thing (I'm pretty certain you'll find such a classic example in many tutorials about relational database design.). Something along the lines of:
CREATE TABLE customer
(id integer,
name varchar(64),
...
PRIMARY KEY (id));
CREATE TABLE product
(id integer,
name varchar(64),
...
PRIMARY KEY (id));
CREATE TABLE order
(id integer,
customer integer,
...
PRIMARY KEY (id),
FOREIGN KEY (customer)
REFERENCES customer
(id));
CREATE TABLE order_product
(order integer,
product integer,
amount integer,
...
PRIMARY KEY (order,
product),
FOREIGN KEY (order)
REFERENCES order
(id),
FOREIGN KEY (customer)
REFERENCES customer
(id));
(order might be a bad choice for a table or column name in some DBMS as it's also a keyword and thus required quoting. So probably chose something else. I used it just for the sake of clarity.)

How do I ensure integrity between unrelated tables?

I just recently started learning database design, and I'm am working with Oracle 11G and SQL Developer.
I have these 3 business rules for a DB:
Each OFFICER must enroll in one and only one INSURANCE COMPANIES. each INSURANCE COMPANY may enroll one or more OFFICERS
Each INSURANCE COMPANY must provide at least five different types of INSURANCE TYPES. Each TYPE OF INSURANCE may be provided by up to 4 INSURANCE COMPANIES or none at all
Each INSURANCE TYPE may be subscribed to by one or more OFFICERS. Each OFFICER may subscribe to up to FIVE different INSURANCE COVERS provided by the same company.
.
.
.
so far, so good, i came up with five TABLES (INS_COY, OFFR, INS_TYPE, PROVIDE, and SUBSCRIBE). PROVIDE and SUBSCRIBE came about as composite tables since the relationships between INS_COY and INS_TYPE, and OFFR and INS_TYPE are both M:M relationships.
PK and FK attributes for each of the table is as below:
INS_COY TABLE
coy_id - PK
OFFR TABLE
offr_id - PK
coy_id - (FK referencing INS_COY.coy_id))
INS_TYPE TABLE
type_id - PK
PROVIDE
coy_id and type_id - (composite PK)
coy_id - (FK referencing COY.coy_id)
type_id - (FK referencing ins_type.type_id)
SUBSCRIBE
naf_no and type_id - (composite PK)
naf_no - (FK referencing offr.offr_id)
type_id (FK referencing ins_type.type_id)
.
.
.
the tables have been sucessfully created, and sample data inserted.
so, the problem is - on the SUBSCRIBE TABLE, HOW DO I ENSURE INTEGRITY THAT THE TYPE_ID ATTACHED TO AN OFFR_ID IS AN INS_TYPE PROVIDED BY THE COY HE IS ENROLLED IN?
sample data tables
i.e ...from the tables, "offr 4250" is enrolled in "coy 1", and "coy 1" doesn't provide "ins_type 13", however, because there's no constraint to check this, "offr 1" is subscribed to "ins_type 13" on the SUBSCRIBE TABLE.
You can do it using controlled redundancy and composite FK constraints:
CREATE TABLE offr (
offr_id INT NOT NULL,
coy_id INT NOT NULL,
PRIMARY KEY (offr_id),
FOREIGN KEY (coy_id) REFERENCES ins_coy (coy_id),
UNIQUE KEY (offr_id, coy_id)
);
I added a composite unique key (offr_id, coy_id) to support a composite FK constraint on the subscribe table.
CREATE TABLE provide (
coy_id INT NOT NULL,
type_id INT NOT NULL,
PRIMARY KEY (coy_id, type_id),
FOREIGN KEY (coy_id) REFERENCES ins_coy (coy_id)
);
The composite primary key here is perfect for a composite FK constraint on the subscribe table.
CREATE TABLE subscribe (
naf_no INT NOT NULL,
coy_id INT NOT NULL,
type_id INT NOT NULL,
PRIMARY KEY (naf_no, type_id),
FOREIGN KEY (naf_no, coy_id) REFERENCES offr (offr_id, coy_id),
FOREIGN KEY (coy_id, type_id) REFERENCES provide (coy_id, type_id)
);
Overlapping composite FK constraints will ensure that an officer can only subscribe to insurance offered by the company he/she is enrolled in. coy_id is logically redundant but required for integrity and there's no risk of update anomalies due to the FK constraints.
Alternatively, you could use triggers to check that the values are related via inner joins:
CREATE TRIGGER check_subscribe BEFORE INSERT OR UPDATE ON subscribe
FOR EACH ROW
WHEN NOT EXISTS (
SELECT 1
FROM offr
INNER JOIN provide ON offr.coy_id = provide.coy_id
WHERE offr.offr_id = new.naf_no AND provide.type_id = new.type_id
)
RAISE_APPLICATION_ERROR (num => -20000, msg => 'Officers can only subscribe to types provided by their company');
Disclaimer: I was unable to test this on SqlFiddle and don't have Oracle installed, but hopefully it'll point you in the right direction.

How to add a unique constraint using a column from another table?

I have 3 tables in SQL Server 2008 R2 that look like these:
A COMPANY may have many LSPs. An LSP may have many SERVICEs.
And I need to make sure that SERVICE_CODE uniquely identifies a SERVICE record within a COMPANY. In other words, COMPANY_ID + SERVICE_CODE should uniquely identify a SERVICE record in the entire system.
For example: COMPANY-A may NOT have 2 services (with 2 different SERVICE_IDs) with the same SERVICE_CODE. But COMPANY-A and COMPANY-B may both have 2 separate SERVICES (again, with different SERVICE_IDs) with SERVICE_CODE = "PREMIUM".
I need something like this:
alter table "SERVICE"
add constraint "SERVICE_Index01"
unique ("COMPANY_ID", "SERVICE_CODE")
But (obviously) this fails because the COMPANY_ID column is not in the SERVICE table.
Thanks in advance for any help.
You could use an indexed view as an external constraint:
CREATE VIEW dbo.CompanyServices
WITH SCHEMABINDING
AS
SELECT
c.COMPANY_ID,
s.SERVICE_CODE
FROM dbo.COMPANY c
INNER JOIN dbo.LSP l ON c.COMPANY_ID = l.COMPANY_ID
INNER JOIN dbo.SERVICE s ON l.LSP_ID = s.LSP_ID
GO
CREATE UNIQUE CLUSTERED INDEX UQ_CompanyServices
ON dbo.CompanyServices (COMPANY_ID, SERVICE_CODE);
The index will make sure there's no duplicates of (COMPANY_ID, SERVICE_CODE) in your data.
Is each company limited to a single LSP? Is Service_Code unique (or could there be two service codes "PREMIUM" with different Service_IDs)?
CREATE TABLE dbo.Company
(
CompanyID INT PRIMARY KEY
-- , ...
);
CREATE TABLE dbo.LSP
(
LSPID INT PRIMARY KEY,
CompanyID INT FOREIGN KEY REFERENCES dbo.Company(CompanyID) -- UNIQUE?
-- , ...
);
CREATE TABLE dbo.Service
(
ServiceID INT PRIMARY KEY
-- , ...
);
CREATE TABLE dbo.LSP_Service
(
LSPID INT FOREIGN KEY REFERENCES dbo.LSP(LSPID),
ServiceID INT FOREIGN KEY REFERENCES dbo.Service(ServiceID),
PRIMARY KEY (LSPID, ServiceID)
);
Add COMPANY_ID to service table.
If you need rows in Service table to be unique by this id it makes sense to keep a foreign key reference in this table.

Many-to-many relations in RDBMS databases

What is the best way of handling many-to-many relations in a RDBMS database like mySQL?
Have tried using a pivot table to keep track of the relationships, but it leads to either one of the following:
Normalization gets left behind
Columns that is empty or null
What approach have you taken in order to support many-to-many relationships?
Keep track of a many-to-many relationship in a table specifically for that relationship (sometimes called a junction table). This table models the relationship as two one-to-many relationships pointing in opposite directions.
CREATE TABLE customer (
customer_id VARCHAR NOT NULL,
name VARCHAR NOT NULL,
PRIMARY KEY (customer_id));
CREATE TABLE publication (
issn VARCHAR NOT NULL,
name VARCHAR NOT NULL,
PRIMARY KEY (issn));
-- Many-to-many relationship for subscriptions.
CREATE TABLE subscription (
customer_id VARCHAR NOT NULL,
FOREIGN KEY customer_id REFERENCES customer (customer_id),
issn VARCHAR NOT NULL,
FOREIGN KEY issn REFERENCES publication (issn),
begin TIMESTAMP NOT NULL,
PRIMARY KEY (customer_id, issn));
You then use the junction table to join other tables through it via the foreign keys.
-- Which customers subscribe to publications named 'Your Garden Gnome'?
SELECT customer.*
FROM customer
JOIN subscription
ON subscription.customer_id = customer.customer_id
JOIN publication
ON subscription.issn = publication.issn
WHERE
publication.name = 'Your Garden Gnome';
-- Which publications do customers named 'Fred Nurk' subscribe to?
SELECT publication.*
FROM publication
JOIN subscription
ON subscription.issn = publication.issn
JOIN customer
ON subscription.customer_id = customer.customer_id
WHERE
customer.name = 'Fred Nurk';
I would use a pivot table, but I don't see where your issues are coming from. Using a simple student/class example:
Student
-------
Id (Primary Key)
FirstName
LastName
Course
------
Id (Primary Key)
Title
StudentCourse
-------------
StudentId (Foreign Key -> Student)
CourseId (Foreign Key -> Course)
Or, as somebody else mentioned in response to your Student/Teacher/Course question (which would have an additional table to store the type of person in the course):
PersonType
----------
Id (Primary Key)
Type
Person
------
Id (Primary Key)
FirstName
LastName
Type (Foreign Key -> PersonType)
Course
------
Id (Primary Key)
Title
PersonCourse
------------
PersonId (Foreign Key -> Person)
CourseId (Foreign Key -> Course)
The Student table contains student information, the Course table stores course information...and the pivot table simply contains the Ids of the relevant students and courses. That shouldn't lead to any null/empty columns or anything.
In addition to Justin's answer: if you make clever use of Foreign Key constraints, you can control what happens when data gets updated or deleted. That way, you can make sure that you do not end up with de-normalized data.