Many-to-Many Relationships across 4 Tables - database

I'm implementing a role base access control system, for which have the following database tables.
groups
---------
id (PK)
name
level
resources
---------
id (PK)
name
roles
---------
id (PK)
name
permissions
-----------
id (PK)
name
description
users
-----------
id (PK)
name
group_id(FK - references id on groups)
role_id(FK - references id on roles)
Groups has a many-to-many relationship with Resources and Roles. So I have the following junction tables.
group_resource
---------------
group_id(FK - references id on groups)
resource_id(FK - references id on resources)
group_role
---------------
group_id(FK - references id on groups)
role_id(FK - references id on roles)
Here is the issue:
Any given role within a group should have permissions for resources assigned to that group only.
I'm not entirely sure what would be the best way to model the relationship between roles, permissions, and resources in the context of group_resource and group_role relationships .
Any suggestions will be highly appreciated.
Thanks.

Here is a possible solution, with a certain degree of redundancy.
groups (id (PK), name, level)
roles (group_id (FK for groups) ,num_role, name) with PK (group_id, num_role)
users (id (PK), name, group_id, num_role) with (group_id, num_role) FK for roles
resource_types (id (PK), name)
group_resources (resource_type_id (FK for resource_types), group_id (FK for groups) with PK both the attributes
permissions (resource_type_id (FK for resource_types), group_id, num_role, description) with (group_id, num_role) FK for roles
With this solution, the application must check during the insertion of a permission, that the resource appear in the group_id specified in the permission, typically with a trigger.
A way of eliminating at all this redundancy (but it seems to me a less satisfying design), is to eliminate the relation group_resources, since all the information can be found through permissions.

-- Group GRP exists.
--
group {GRP}
PK {GRP}
-- Role ROL exists.
--
role {ROL}
PK {ROL}
-- Resource RES exists.
--
resource {RES}
PK {RES}
-- Role ROL exists within group GRP.
--
group_role {GRP, ROL}
PK {GRP, ROL}
FK1 {ROL} REFERENCES role {ROL}
FK2 {GRP} REFERENCES group {GRP}
-- Group GRP is assigned resource RES.
--
group_resource {GRP, RES}
PK {GRP, RES}
FK1 {GRP} REFERENCES group {GRP}
FK2 {RES} REFERENCES resource {RES}
-- Permission PER exists.
--
permission {PER}
PK {PER}
-- Permission PER is granted to role ROL
-- in group GRP for resource RES.
--
group_resource_permission {GRP, RES, ROL, PER}
PK {GRP, RES, ROL}
FK1 {GRP, RES} REFERENCES group_resource {GRP, RES}
FK2 {GRP, ROL} REFERENCES group_role {GRP, ROL}
FK3 {PER} REFERENCES permission {PER}
-- User USR is assigned role ROL in group GRP.
--
user {USR, GRP, ROL}
PK {USR}
FK1 {ROL} REFERENCES role {ROL}
FK2 {GRP} REFERENCES group {GRP}
-- User USR in role ROL of group GRP,
-- has permission PER to resource RES.
--
CREATE VIEW user_resource_permission
AS
SELECT u.USR
, x.RES
, x.PER
, u.GRP
, u.ROL
FROM user as u
JOIN group_resource_permission as x ON x.GRP = u.GRP
AND x.ROL = u.ROL ;
Note:
All attributes (columns) NOT NULL
PK = Primary Key
AK = Alternate Key (Unique)
SK = Proper Superkey (Unique)
FK = Foreign Key

Related

Database schema for a defect tracking system

I want to build the following defect detection system in SQL Server. The interface will be built using ASP.NET . but currently i am struggled on how to build the Database tables the relation between these tables.
the system allow to create a report >> select the report type,Equipment ID & other info >> select the wanted categories (by choosing Y or N) >> and for the selected category >> select the defect details and enter the comments..
I came out with this schema (Table names & Columns):-
Equipment
ID
Name
Operator
ID
Name
Report Type
ID
Name
Report
ID
Operator ID (FK to Operator),
Name
Equipment ID (FK to Equipment)
Type ID (FK to Report Type)
Date/Time
Comments
ReportCategory
ID
Name
Part
ID
Name
ReportCategory
Report ID (FK to Reports) -->PK
Category ID (FK to Category) --> PK
Yes/no
DefectDetailesLookup
Part ID (FK to Part) ---> PK
Cateogry ID (FK to Cateogry) ---> PK
ReportDefectDetails
ReportID (FK to Report) --> PK
Category ID (FK to Category) --> PK
Part ID (FK to Part)-->PK
Comment
Yes/No
so are the schema valid? or i am missing something? thanks
It would work.
There are a few things worth giving a thought for future changeability: Without fully understanding your applications domain: Give composite PKs a second thought. It is not necessarily a bad practise to use them, but if you use them make sure they are an integral part to the Entities Identity. And if you are not sure, I'd recommend to remove them and rather use an own Identity column for your Entity. Otherwise you are bound to having i.e. a Category for every ReportDefectDetail.
If you are not dependent on an existing database and assuming you already have your repository classes set up, give ef core and code-first a try. Also DDD (domain driven design) is a worthy read. Modern db models are mostly code driven/domain driven. The time of dbs dictating how the code should be written are gone.
Aside from that:
little typo here: DefectDetail_e_sLookup
ReportCategory => exists two times. I guess the upper one is just Category
give your yes/no columns meaningful names, like isDisplayed
-- Defect DEF named DEF_NME, with comment DEF_CMT exists.
--
defect {DEF, DEF_NME, DEF_CMT}
PK {DEF}
AK {DEF_NME}
-- Defect category CAT named CAT_NME exists.
--
dcat {CAT, CAT_NME}
PK {CAT}
AK {CAT_NME}
-- Defect DEF is in defect category CAT.
--
defect_category {DEF, CAT}
PK {DEF, CAT}
FK1 {DEF} REFERENCES defect {DEF}
FK2 {CAT} REFERENCES dcat {CAT}
-- Part PRT named PRT_NME exists.
--
part {PRT, PRT_NME}
PK {PRT}
AK {PRT_NME}
-- It is possible for part PRT to have defect DEF.
--
part_defect {PRT, DEF}
PK {PRT, DEF}
FK1 {PRT} REFERENCES part {PRT}
FK2 {DEF} REFERENCES defect {DEF}
-- Equipment EQP named EQP_NME exists.
--
equipment {EQP, EQP_NME}
PK {EQP}
AK {EQP_NME}
-- Equipment EQP contains part PRT.
--
equipment_part {EQP, PRT}
PK {EQP, PRT}
FK1 {EQP} REFERENCES equipment {EQP}
FK2 {PRT} REFERENCES part {PRT}
-- Operator 0PR named OPR_NME exists.
--
operator {0PR, OPR_NME}
PK {0PR}
AK {OPR_NME}
-- Report type RTY named RTP_NME exists.
--
report_type {RTY, RTP_NME}
PK {RTY}
AK {RTP_NME}
-- Report category RCT named RCT_NME exists.
--
report_cat {RCT, RCT_NME}
PK {RCT}
AK {RCT_NME}
-- Report REP, of report-type RTY, named REP_NME,
-- categorized in report-category RCT,
-- was submitted by operator OPR on date-time DTE,
-- for equipment EQP with comments REP_CMT.
report{REP, RTY, REP_NME, RCT, OPR, DTE, EQP, REP_CMT}
PK {REP}
AK {REP_NME}
SK {REP, EQP}
FK1 {RTY} REFERENCES report_type {RTY}
FK2 {OPR} REFERENCES operator {0PR}
FK3 {EQP} REFERENCES equipment {EQP}
FK4 {RCT} REFERENCES report_cat {RCT}
-- Defect DEF for part PRT of equipment EQP is reported in
-- report-detail number DET_NO of report REP; with
-- additional comments DET_CMT.
--
report_detail {REP, DET_NO, EQP, PRT, DEF, DET_CMT}
PK {REP, DET_NO}
FK1 {REP, EQP} REFERENCES report {REP, EQP}
FK2 {EQP, PRT} REFERENCES equipment_part {EQP, PRT}
FK3 {PRT, DEF} REFERENCES part_defect {PRT, DEF}
Note:
All attributes (columns) NOT NULL
PK = Primary Key
AK = Alternate Key (Unique)
SK = Proper Superkey (Unique)
FK = Foreign Key

Creating multiple relations under a single entity (Database Design)

I am trying to design a relational database (postgres) which contains multiple tables under a single entity. In this example I have a store.
The store has many customers, staff, products. They are all related to the store through a "store_id"
I want to also link customers to a staff member. But I can't just add staff_id to the customers table, because this could allow a customer to be associated with a staff member from any store.
Is it possible to allow customers to be related only to staff which both the customer and staff are a member of?
Basically how do I prevent the below from happening?
Thanks for reading.
Solved this by applying a multi column foreign key constraint.
For customers, I keep the store_id foreign key, add a staff_id foreign key. Then also add a foreign key constraint against staff.store_id and staff.id
staff_id integer REFERENCES staff(id),
store_id integer REFERENCES stores(id),
CONSTRAINT customers_staff_id_store_id_fkey FOREIGN KEY (staff_id, store_id) REFERENCES staff(id, store_id)
This enforces a rule so customers can only be associated to staff of the same store
-- Person (user) USR exists.
--
user {USR}
PK {USR}
-- Store STO exists.
--
store {STO}
PK {STO}
-- Staff member (person) USR works at store STO.
--
staff {USR, STO}
PK {USR}
SK {USR, STO}
FK1 {USR} REFERENCES user {USR}
FK2 {STO} REFERENCES store {STO}
-- Customer (person) USR shops at store STO.
--
customer {USR, STO}
PK {USR}
SK {USR, STO}
FK1 {USR} REFERENCES user {USR}
FK2 {STO} REFERENCES store {STO}
-- Staff member STF manages account of customer CST
-- in store STO.
--
acc_mng {CST, STF, STO}
PK {CST}
FK1 {CST, STO} REFERENCES customer {USR, STO}
FK2 {STF, STO} REFERENCES staff {USR, STO}
Note:
All attributes (columns) NOT NULL
PK = Primary Key
AK = Alternate Key (Unique)
SK = Proper Superkey (Unique)
FK = Foreign Key

Using linking table for restricting entities in many-to-many relationship otherwise no restrictions

I have a many-to-many relationship between PromoCode and User. A user can have many promocodes and a promoCode can be valid for many users. The default case is that a promoCode will be valid for all users.
User(userId,...)
PromoCode(promoCodeId,...)
In this many-to-many relationship, I have created a secondary table UserPromoCode(userId, promoCodeId) in which we store only promocodes which are restricted for few customers. How can I deal the default case?
Do I have to add records in UserPromoCode table for all users? It will be obviously expensive when a new promoCode is created
Or do I have to save only restricted ones and apply if else condition in my application logic like if there is no record for a promoCode in UserPromoCode table, the promocode applies to all?
In short, how we deal with problem of optional restricting an entity for some other entity otherwise by default no restriction in many-to-many relationships?
I don't want to apply if else conditions at application logic. I simply want to apply a query that can give me all PromoCodes for a user (restricted or unrestricted ones)
-- Promo code CDE exists.
--
promo {CDE}
PK {CDE}
-- Promo code CDE is special (restricted).
--
promo_special {CDE}
PK {CDE}
FK {CDE} REFERENCES promo {CDE}
-- Promo code CDE is available to all users.
--
CREATE VIEW promo_all
AS
SELECT CDE from promo
EXCEPT
SELECT CDE from promo_special ;
-- User USR exists.
--
user_ {USR}
PK {USR}
Option 1
A subset of (special) users qualify for all special promo codes.
-- User USR qualifies for all special promo codes.
--
user_special {USR}
PK {USR}
FK {USR} REFERENCES user_ {USR}
-- User USR qualifies for promo code CDE.
--
CREATE VIEW user_promo
AS
SELECT USR, CDE
FROM user_
CROSS JOIN promo_all
UNION
SELECT USR, CDE
FROM user_special
CROSS JOIN promo_special ;
Option 2
Some users qualify for some of special promo codes.
-- User USR qualifies for special promo code CDE.
--
user_special {USR, CDE}
PK {USR, CDE}
FK1 {USR} REFERENCES user_ {USR}
FK2 {CDE} REFERENCES
promo_special {CDE}
-- User USR qualifies for promo code CDE.
--
CREATE VIEW user_promo
AS
SELECT USR, CDE
FROM user_
CROSS JOIN promo_all
UNION
SELECT USR, CDE
FROM user_special ;
For Both Options
To get all promo codes for a specific user.
-- Specific user (USR = specific_user) qualifies
-- for promo code CDE.
--
SELECT CDE FROM user_promo WHERE USR = specific_user ;
Note:
All attributes (columns) NOT NULL
PK = Primary Key
FK = Foreign Key

Database design for employee, department and role hierarchy

Suppose I have employees and departments and employee role where one employee can belong to a different department with a different role.
For example, Emp 1 belongs to Dept 1 with a role manager. where the same employee can belong to Dept 2 with a role service-man.
Each employee also has a child hierarchy like Emp 2, Emp 3 belongs to Dept 1 with role assistant and their parent is Emp 1.
In this case what will be the best solution for designing this concept. Please share your opinion.
Consider the entities and attributes:
Employees:
id,
name
Departments:
deptID,
dept_name
Roles:
role_id,
role_name
I'll try to state the business domain as you've outlined it, and then turn that into a schema suggestion.
The system has 0 or more employees
The system has 0 or more departments
The system has 0 or more roles
<<EDIT: your comment says that the "parent" role is department-specific>>
An employee belongs to 1 or more departments, and within that department has exactly one role and one parent (a parent is another employee)
Employee
------------
Employee_id (pk)
Name
Roles
------
Role_id (pk)
Name
Departments
-----------
Department_id (pk)
Name
Employee_deparment_role
-------------------------
employee_id (pk, fk)
department_id (pk, fk)
role_id (pk, fk)
Parent_id (pk, fk to employees)
This model only captures one state - it doesn't allow people to change departments or roles, or "parent", but you didn't mention that as a requirement.

What's difference between #JoinColumn and #JoinTable in One-To-Many relationship?

I encountered Hibernate problem, What's difference between #JoinColumn and #JoinTable in One-To-Many relationship?
Thanks in advance.
JoinColumn uses... a join column to map the asociation:
Order Line
----- ----
id id
... order_id (FK to order.id)
...
JoinTable uses... a join table to map the association:
Order Order_Line Line
----- ---------- ----
id order_id (FK to order.id) id
... line_id (FK to line.id, unique) ...

Resources