Check Constraint Usage - sql

I am trying to make a constraint that will keep ids unique for specific users.
Each user is a separate entity within the world so 2 people having 1 as id is not a problem. I just don't want one person to have the same id twice.
For example:
This would be acceptable:
User Id
John 1
John 2
Alice 1
Alice 2
This would not be ok:
User Id
John 1
John 1 -- problem
Alice 1
Alice 2

Just add a Unique constraint over both columns to your CREATE TABLE statement:
CREATE TABLE person(
... -- more columns
username text
,person_id int
,UNIQUE (username, person_id)
);
That does it. I see that #Hamlet and #Frank already commented likewise.

Creating a unique index on these two columns would also work. This is usually what happens under the covers to enforce the constraint.

Related

Validate whether value in one table is the same as in related table - performance

Let's say I have two tables and I'm doing all the operations in .NET Core 2 Web API.
Table A:
Id,
SomeValue,
TeamName
Table B:
Id,
Fk_Id_a (references Id in table A),
OtherValue,
TeamName
I can add and get records from table B indepedently.
But for every record in Table B TeamName has to be the same as for it's corresponidng Fk_Id_a in Table A.
Assume these values comes in:
{
"Fk_Id_a": 3,
"SomeValue": "test val",
"TeamName": "Super team"
}
Which way would be better to check it in terms of performance? 1ST way requires two connections, when 2nd requires storing some extra keys etc.
1ST WAY:
get record from Table A for Fk_Id_a (3),
check if TeamName is the same as in coming request (Super team),
do the rest of the logic
2ND WAY:
using compound foreign keys and indexes:
TableA has alternate unique key (Id, TeamName)
TableB has foreign compound key (Fk_Id_a, TeamName) that references TableA (Id, TeamName)
SQL SCRIPT TO SHOW:
ALTER TABLE Observation
ADD UNIQUE (Id, PowelTeamId)
GO
ALTER TABLE ObservationPicturesId
ADD FOREIGN KEY(ObservationId, PowelTeamId)
REFERENCES Observation(Id, PowelTeamId)
ON DELETE CASCADE
ON UPDATE CASCADE
EDIT: Simple example how the tables might look like. TeamName has to be valid for FK referenced value in Table A.
Table A
ID | ObservationTitle | TeamName
---------------------------------------
1 | Fire damage | CX_team
2 | Water damage | CX_team
3 | Wind damage | Dd_WP3
Table B
ID | PictureId | AddedBy | TeamName | TableA_ID_FK
-----------------------------------------------------
1 | Fire | James | CX_team | 1
2 | Water | Andrew | CX_team | 1
3 | Wind | John | Dd_WP3 | 3
Performance wise, the 2nd option would be faster because there is no comparison to check (the foreign key will force that they match when inserting, updating or deleting) when selecting the rows from the table. It would also make a unique index on table A.
That being said, there is something very fishy about the structure you mention. First of all why is the TeamName repeated in table B? If a row in table B is "valid" only when the TeamName match, then you should enforce that no row should be inserted with a different TeamName, throught the ID foreign key (and not actually storing the TeamName value). If there are records on table B that represent another thing rather than the entity that is linked to table A then you should split it onto another table or just update the foreign key column when the team matches and not always.
The issue is that you are using a foreign key as a partial link, making the relationship valid only when an additional condition is true.

How to create this `check constraint`

I have two tables:
People:
Id | OrgId | Name
-----------------
1 10 Sam
2 10 Dana
3 12 Max
Id is a primary key. OrgId is foreign key to other table.
And second table Cars:
Id | Name | OrgId | PersonId
----------------------------
1 Volvo 10 1
2 BMW 10 2
Here: Id is a primary key. PersonId is a foreign key to People table. OrgId is foreign key to Organization table.
So I have Person which are attached to Organization and I have Cars which are attached to Organization and Person.
I need to guarantee that it will be impossible to attach Car from one Organization to Person from another Organization. The record:
Id | Name | OrgId | PersonId
----------------------------
1 Volvo 12 1
must be impossible because Car belongs to Organization with ID = 12, but Person belongs to Organization with ID = 10.
What is the best way to do it ?
I see two ways:
Foreign key using two fields People (Id + OrgId) <-> Cars (PersonId + OrgId).
But in this case I need to create one additional unique index on the table People ('Id+OrgId`).
Trigger on the table Cars.
What do you recommend to use in this case ?
My first reaction is to look up the organization using the person column. But, that doesn't really fit the situation -- cars are owned by organizations independently of people. So, you might need the organization, even if no person is assigned.
So, add a new key to people:
alter table people add constraint unq_people_orgid_id unique (orgid, id);
Then use this for the foreign key reference in cars:
alter table cars add constraint
foreign key (orgid, personid) references people(orgid, id);
Note that the second key is redundant. But it allows a reference that includes the organization.
I wouldn't use OrgId in your cars table, it violates normalization rules. You can use a query to get the organization information for the car using the PersonId.

Eloquent Foreign Key to Same Table

In Laravel 4's Eloquent,
i have a table user and a field user.friend_id which is an also an id of a user..
but when i try to create a new user with friend_id = 0, the foreign key fails..
and when friend_id = 1, it succeeds.
I have this in my user's schema builder
$table->unsignedInteger('friend_id')->default(0)->nullable();
what should I be doing here?
should i have just created a pivot table instead?
thanks!
You should not set default value 0 for a null able foreign key.
Correct way:
$table->unsignedInteger('friend_id')->nullable();
Explanation:
$table->unsignedInteger('friend_id')->default(0)->nullable();
When you try to insert a new record, and leave the friend_id blank.
The database takes the default value for the field ie: 0
since it's a foreign key, to maintain relational integrity, it will look for a record having primary key 0. (which naturally does not exist)
Assuming you can have more than one friend, then yes, you should have a pivot table
User table
id | name
1 | Laurence
2 | Ben
3 | Jane
Users_Friend table
user_id | friend_id
1 | 2
1 | 3
This means Laurence is friends with Ben and Jane

Constrain a table such that each account can have one of another table

I have a table which has these columns:
Id (Primary Key): the id.
OwnerId (Foreign Key): the id of the owner, which resides in another table.
TypeId (Foreign Key): the type of thing this record represents. There are a finite number of types, which are represented in another table. This links to that table.
TypeCreatorId (ForeignKey): the owner of the type represented by TypeId.
SourceId (Foreign Key): this isn't important to this question.
I need to constrain this table such that for each Id, there can be only one of each TypeCreatorId. I hope that makes sense!
For SQL Server, you have two options:
create a UNIQUE CONSTRAINT
ALTER TABLE dbo.YourTable
ADD CONSTRAINT UNIQ_Id_TypeCreator UNIQUE(Id, TypeCreatorId)
create a UNIQUE INDEX:
CREATE UNIQUE INDEX UIX_YourTable_ID_TypeCreator
ON dbo.YourTable(Id, TypeCreatorId)
Basically, both things achieve the same thing - you cannot have two rows with the same (Id, TypeCreatorId) values.
Simply create a unique index on OwnerId and TypeCreatorId.
An example using MySQL (sorry, I don't use SQL Server):
alter table yourTable
add unique index idx_newIndex(OwnerId, TypeCreatorId);
Example. I'll just put here what would happen with this new unique index:
OwnerId | TypeCreatorId
--------+--------------
1 | 1
1 | 2 -- This is Ok
2 | 1 -- Ok too
2 | 2 -- Ok again
1 | 2 -- THIS WON'T BE ALLOWED because it would be a duplicate

Better way to define role restrictions in the database tables

Role table
RoleID Desc
1 primary
2 secondary
3 alternate
Users
UserID Name
1 ann
2 saylor
3 jim
4 ken
5 kathy
Route table
RouteID Name
1 x
2 y
RouteRoleUser table
RouteID RoleID UserID
1 primary ann
1 secondary saylor
1 alternate jim
1 alternate ken
1 alternate kathy
I have a grid which shows the following:
Route | Primary Pumper | Secondary Pumper | Alternate Pumpers (comma separated)
x ann saylor jim, ken, kathy
My requirements are:
Any route can have only one primary user
Any route can have 0 or one secondary user
Any route can have 0 or more alternate users
All users of a route are unique
How can I have the requirements restriction from a db design perspective in the RouteRoleUser table? Currently if I make Route, Role and User as candidate key, it does not
stop anyone to add two primary users for a route.
Is there a better way?
For the "Any route can have N number of (type) user(s)" rule, you could validate this by using an INSTEAD OF INSERT trigger and preventing the insert. I personally handle this type of logic at the application or stored procedure level.
For the "All users of a route are unique" you can enforce this with a UNIQUE constraint on RouteID, UserID.