UserRoles table with no PK - sql-server

I have the following tables (among others):
Users
Departments
Roles
UserRoles
The UserRoles table has the following fields:
UserId
RoleId
DepartmentId (NULL)
The idea here is I can give a user a specific role, for specific department(s), if the DepartmentId is NULL, then this role applies to all departments.
The problem here I cannot make a composite primary key out of the three fields in the UserRoles table since the DepartmentId is nullable.
Should I just go with a unique index without a primary key since I cannot have a primary key for the first two columns only (that will prevent the user from having the same role to multiple departments), or should I change the whole structure to something else (any ideas will be appreciated).

I would make DepartmentID not null and assign a value of 0 to symbolize all departments. This will help you both in creating a PK and in queries where now you can simply say where DepartmentID = 0 instead of where DepartmentID is null.

Related

Is there a trigger object I can write to ensure a foreign key, which was left nullable when it was written, is filled in?

I have a database orders table with a foreign key that refers to a customer id in another table. the customer and orders table is a one-to-many relationship. There are several orders in the orders table that do not have a customer id (the foreign key) included in the orders table because the foreign key column was left nullable:
create table orders1
(
orderID int,
customerID int,
customerLName varchar(50),
customerFName varchar(50),
orderTotal float,
primary key (orderID),
foreign key (customerID) references customer1(customerID) -- left nullable
);
I can't go back an fix the entries that have no customer IDs attached, but is there a trigger object I can create that will alert the user if they do not fill in the customer ID value in the future?
No, there is no trigger/code you can write that will be able to guess what customer id a random order should belong to if the insert omits the customer id.
Your best move is to fix the rows that have null customer id and make the FK not nullable.
One reasonable way to fix the rows is to create a dummy customer record and associate the orphaned orders to it. Once that is done, and you alter the column to not null, you will have stopped the rot and can sift through the data to try to figure out what customer those orders actually belong to. You might find the answer in application logs, or perhaps other entities such as payment etc, or maybe the orders are so old nobody cares.

Is there is a constraint to make sure one column has and only matched column

I have a problem to set correct constraint to make sure one column has and only has one matched column within the table.
For example, company Apple has Bloomberg ticker AAPL:US and only has this ticker. Otherwise, SQL Server will notice there is a error.
I try to use constraint with unique, but it does not work.
I imagine that your schema might be a standard one using a junction table. That is, your tables might look something like:
company (id, name)
ticker (id, name)
company_ticker (id_company, id_ticker)
That is, the company_ticker table is a junction table which stores the relationships between companies and tickers. Normally, this table would by default be many-to-many. But if you want to restrict a company to having only one ticker, then you may place a unique constraint on the id_company column:
CREATE TABLE company_ticker (
id_company INT NOT NULL,
id_ticker INT NOT NULL,
PRIMARY KEY (id_company, id_ticker),
CONSTRAINT cnstr UNIQUE (id_company)
);
With the above unique constraint in place, your schema will only allow a given company to have one relationship with some ticker.

A better database design on SQL Server?

In SQL Server, I need to design a User table. It should have a UserID (int), a RoleID (int) and a UserName (nvarchar(255)).
A user can be assigned with a name but possibly multiple roles so a UserId may correspond to multiple RoleIDs. This makes it difficult to assign primary key to UserID as UserID may duplicate.
Is there any better design other than breaking it up into multiple tables?
You should have:
1. a user table with UsertId(int), UserName (Varchar)
2. a role table with RoleId(int), RoleName(Varchar)
3. a user_role table with user_id(int), role_id(int)
And don't forget to add the proper indexing and foreign keys.
Ye, have a table Roles, then RolesUsers with UserID and RoleID, and lastly a Users table
edit: where the UserID + RoleID in the RolesUsers are a composite key

Avoiding duplicates in designing One to Many relationship

I went through many threads and couldn't figure it out. Sorry if this is a duplicate question. Consider the following setup.
1) Employee => (ID,Name)
2) Department => (ID,Name,location,Clerk,Accountant,Middle-manager,Group-manager,Regional-manager,Active)
Department can have many Clerks, Accountants, Middle-managers and so on. They are just employees from the Employee table. Need a better database schema (flexible like, adding up a new column as Divisional-Manager must be easy) for Department entity with NO data duplication, NO update anomalies and NO / less junction tables.
Thanks in advance! :)
You need something like this;
CREATE TABLE department(
dept_id int NOT NULL,
dept_name char(10) NULL,
CONSTRAINT PK1 PRIMARY KEY NONCLUSTERED (dept_id)
)
go
CREATE TABLE department_employee(
id int NOT NULL,
dept_id int NOT NULL,
emp_id int NOT NULL,
CONSTRAINT PK3 PRIMARY KEY NONCLUSTERED (id)
)
go
CREATE TABLE employee(
emp_id int NOT NULL,
emp_name char(10) NULL,
CONSTRAINT PK2 PRIMARY KEY NONCLUSTERED (emp_id)
)
go
ALTER TABLE department_employee ADD CONSTRAINT Refdepartment1
FOREIGN KEY (dept_id)
REFERENCES department(dept_id)
go
ALTER TABLE department_employee ADD CONSTRAINT Refemployee2
FOREIGN KEY (emp_id)
REFERENCES employee(emp_id)
go
You have a many-to-many relationship so you need a third association (junction) table - you can't avoid it.
DepartmentMember => (DepartmentId, EmployeeId, MembershipRole)
Why don't you want this?
Employee =>(ID,name, department_ID, position_ID, Active)
Position =>(ID, name, Active)
Department => (ID,Name,location,Active)
Department =>(ID,employeeID,location,active)
Employee =>(EmployeeID,name, position)
I think that would be a much better way of organizing your tables. This assumes that active is a property of the department, else move it to the employee table.
Assuming an employee can only work in 1 department. IF not, then yes, you need a third table to avoid duplication
Employee
ID, Name, EmployeeType, DepartmentID
(pk on ID, EmployeeType)
Department
ID, Name, Active
Position/Title is very much contextual
to Department. One can be a
Regional-Manager in one department and
can additionally takes Consultant
position in another department.
Then , the department and the Employee is many-to-many. The Employee to the position is also many-to-many. If you need flexibility ,like adding a new title for a department , the junction tables are necessary. You cannot avoid it.
You can refer to the following Table structure for reference:
Employee
-----------------------
EmployeeID (PK)
EmployeeName
Active
Department
-------------------------
DepartmentID (PK)
DepartmenName
Location
Position
----------------------------
PositionID (PK)
PositionDescription (eg.Clerk, Accountant etc)
EmployeePosition
----------------------------
EmployeeID (FK to Employee.EmployeeID )
DepartmentID (FK to Department.DepartmentID)
PositionID (FK to Position.PositionID )
If the Position/Title is fixed to
Employee instead of Department.i.e. An
employee who is clerk and can be in
that position to one or many dept.,
how can we go about it?
Do you mean that in an extreme case , many employees can have their own special titles ? and they belong to many departments? If yes ,suppose a employee ID 123 has a special title called "The Special One" , and it belongs to the IT , Account and Sales department . You first create this title (i.e "The Special One" ) in the Position table and get the Position.PositionID.
Then you insert 3 records for Employee.EmployeeID 123 into EmployeePosition table using this Position.PositionID and the Department ID of IT , Account , Sales departments.

Add ANOTHER primary key to a table which is UNIQUE

I'm having problems with adding another primary key to my table.
I have 3 columns:
Account ID (Identity)
EmailID
Data field
When I made the table I had this to make the Account ID and the Email ID unique.
PRIMARY KEY (AccountID, EmailID)
I thought that would make my emailid unique, but then after I tried inserting another row with the same emailid it went through.
So I thought I missed something out.
Now for my question:
IF, I had to use alter, how do I alter the table/PK Constraint to modify the EmailID field and make it Unique?
IF I decided to drop the table and made a new one, how do I make those two primary keys unique?
You may ALTER the table and add a new UNIQUE CONSTRAINT on the EmailID column.
-- This will create a constraint which enforces that the field EmailID
-- have unique values
ALTER TABLE Your_Table_Name
ADD CONSTRAINT unique_constraint_name UNIQUE (EmailID)
It's worth noting though, that altering the table to add this new unique constraint doesn't mean that you have to drop the other PRIMARY KEY constraint that you have added for the (AccountID, EmailID) pair. That is, of course, unless your business logic dictates it.
When you make the grouping of (AcountID, EmailID) the PRIMARY KEY it specifies that both the AcountID and EmailID participate in uniquely identifying each individual record in that table. So, that means that you could have the following records in the table:
AccountID | EmailID | Other Fields
----------------------------------------------------------
100 | user#company.com | ....
101 | user2#othermail.com | ....
100 | user_alternate#mail.com | ....
In the previous example it is possible to have two records with the same AccountID, and that is valid because the PRIMARY KEY specifies that only the (AccountID, EmailID) pair has to be unique - which it is. It makes no stipulation about AccountID being unique independently.
In conclusion, you probably want to add yet another UNIQUE constraint on AccountID. Or simply make the AccountID alone the PRIMARY KEY and then add a UNIQUE constraint on EmailID.
If both AccountID and EmailID are candidate keys then only one can be the PK the other one will need a unique constraint.
From the POV of SQL Server it doesn't matter which one you choose as the PK. Foreign Key's can reference either the PK or a unique constraint but given that the PK is the clustered index by default it probably makes sense to choose AccountID as this is presumably narrower and more stable.
It sounds like an incorrect Primary key. It's more likely that emailID is intended to be your natural key but for some reason (maybe a development standard in your organization?) you want to use a surrogate ID, AccountID but you still intend for both email ID and surrogate ID to both be unique and have a one to one relationship. If this is true then your primary key should be AccountID and you should place a unique constraint on EmailID.
If you were to recreate the table, it could look like this. I assumed EmailID was referencing an email table instead of being an email address.
CREATE TABLE dbo.AccountEmails
(
AccountID int not null identity(1,1),
EmailID int not null,
Data varchar(max) null,
constraint PK_AccountEmails PRIMARY KEY //this is a unique single column primary key
(
AccountID
),
constraint FK_AccountEmails_EmailID FOREIGN KEY dbo.Email(EmailID) ON //this makes sure EmailID exists in the Email table
(
EmailID
),
constraint UQ_AccountEmails_EmailID UNIQUE //unique single column unique constraint
(
EmailID
),
constraint UQ_AccountEmails_AccountID_EmailID UNIQUE //the combination of AccountID and EmailID is also unique
(
AccountID,
EmailID
)
)
Given the fact that AccountID and EmailID are both seperately unique, I'm not sure UQ_AccountEmails_AccountID_EmailID is really necessary.

Resources