checking foreign key in SQL, is it right? [closed] - sql

Closed. This question needs details or clarity. It is not currently accepting answers.
Want to improve this question? Add details and clarify the problem by editing this post.
Closed 7 years ago.
Improve this question
I need just little your help, can you just check if have I done foreign keys properly in SQL Server?
I'm new in SQL that is why sorry for stupid question.
If everything right, can I start to fill data?
--CREATING EMPLOYEE TABLE
CREATE TABLE EMPLOYEE(
[ID] INT IDENTITY(1,1) NOT NULL,
[FIRST_NAME] NVARCHAR(25) NOT NULL,
[LAST_NAME] NVARCHAR(25) NOT NULL,
[EMAIL] nvarchar(60) NOT NULL CONSTRAINT UQ_EMPLOYEE_email UNIQUE,
[PHARMACY_ID] INT NOT NULL,
CONSTRAINT PK_EMPLOYEE_ID PRIMARY KEY (ID));
--CREATING PHARMACY TABLE
CREATE TABLE PHARMACY (
[ID] INT IDENTITY(1, 1) NOT NULL,
[NAME] NVARCHAR(25),
[ADDRESS] NVARCHAR(25) NULL,
[PHONE] nvarchar(24) NULL CHECK(PHONE like '(___)-__-___ __ __'),
[EID] [INT] NOT NULL
CONSTRAINT PK_PHARMACY_ID PRIMARY KEY (ID));
--CREATE SUPPLIERS TABLE
CREATE TABLE SUPPLIERS(
[ID] INT IDENTITY(1,1) NOT NULL,
[NAME] NVARCHAR(25),
[ADDRESS] NVARCHAR(25) NULL,
[DRUGSID] [INT] NOT NULL,
CONSTRAINT PK_SUPPLIERS_ID PRIMARY KEY (ID));
--CREATE TABLE DRUGS
CREATE TABLE DRUGS(
[ID] INT IDENTITY(1,1) NOT NULL,
[NAME] NVARCHAR(25),
[QUANTITY] INT NULL,
[ORDERID] [INT] NULL,
[SUPPLIERID] [INT] NULL,
CONSTRAINT PK_DRUGS_ID PRIMARY KEY(ID));
--CREATEING TABLE ORDERS
CREATE TABLE ORDERS (
[ID] INT IDENTITY(1,1) NOT NULL,
[ONAME] NVARCHAR(25) NOT NULL,
[ODATE] DATETIME,
[OQUANTITY] INT NOT NULL,
[SUPPLIERID] [INT] NOT NULL,
[DRUGID] [INT] NOT NULL,
CONSTRAINT PK_ORDERS_ID PRIMARY KEY(ID));
--CREATING TABLE MANAGER TABLE
CREATE TABLE MANAGER (
[PASSPORTNO] INT IDENTITY(1,1) NOT NULL,
[HOURLYPAY] DECIMAL(5,2) NULL,
[LANGUAGE_SKILLS] NVARCHAR(25) NULL
CONSTRAINT PK_MANAGER_NO PRIMARY KEY (PASSPORTNO));
--CREATING TABLE SALES ASSISTANT
CREATE TABLE SALES_ASSISTANT (
[PASSPORTNO] INT IDENTITY(1,1) NOT NULL,
[SALARY] DECIMAL(5,2) NULL
CONSTRAINT PK_SALES_ASSISTANT_NO PRIMARY KEY (PASSPORTNO));
-- FOREIGN KEYs CREATION
ALTER TABLE EMPLOYEE ADD CONSTRAINT FK_PHARMACYID FOREIGN KEY(PHARMACY_ID)
REFERENCES PHARMACY(ID) ON DELETE CASCADE ON UPDATE CASCADE
ALTER TABLE PHARMACY ADD CONSTRAINT FK_EID FOREIGN KEY(EID)
REFERENCES EMPLOYEE(ID) ON DELETE NO ACTION ON UPDATE NO ACTION
ALTER TABLE SUPPLIERS ADD CONSTRAINT FK_DRUGID FOREIGN KEY(DRUGSID)
REFERENCES DRUGS(ID) ON DELETE NO ACTION ON UPDATE NO ACTION
ALTER TABLE DRUGS ADD CONSTRAINT FK_ORDERID FOREIGN KEY(ORDERID)
REFERENCES ORDERS(ID) ON DELETE NO ACTION ON UPDATE NO ACTION
ALTER TABLE DRUGS ADD CONSTRAINT FK_SUPPLIERS FOREIGN KEY(SUPPLIERID)
REFERENCES SUPPLIERS(ID) ON DELETE NO ACTION ON UPDATE NO ACTION
ALTER TABLE ORDERS ADD CONSTRAINT FK_SUPPLIERS_OR FOREIGN KEY(SUPPLIERID)
REFERENCES SUPPLIERS(ID) ON DELETE NO ACTION ON UPDATE NO ACTION
ALTER TABLE ORDERS ADD CONSTRAINT FK_DRUGID_OR FOREIGN KEY(DRUGID)
REFERENCES DRUGS(ID) ON DELETE NO ACTION ON UPDATE NO ACTION

You can check the foreign keys you have set with this query
SELECT
KCU1.CONSTRAINT_NAME AS FK_CONSTRAINT_NAME
,KCU1.TABLE_NAME AS FK_TABLE_NAME
,KCU1.COLUMN_NAME AS FK_COLUMN_NAME
,KCU1.ORDINAL_POSITION AS FK_ORDINAL_POSITION
,KCU2.CONSTRAINT_NAME AS REFERENCED_CONSTRAINT_NAME
,KCU2.TABLE_NAME AS REFERENCED_TABLE_NAME
,KCU2.COLUMN_NAME AS REFERENCED_COLUMN_NAME
,KCU2.ORDINAL_POSITION AS REFERENCED_ORDINAL_POSITION
FROM INFORMATION_SCHEMA.REFERENTIAL_CONSTRAINTS AS RC
INNER JOIN INFORMATION_SCHEMA.KEY_COLUMN_USAGE AS KCU1
ON KCU1.CONSTRAINT_CATALOG = RC.CONSTRAINT_CATALOG
AND KCU1.CONSTRAINT_SCHEMA = RC.CONSTRAINT_SCHEMA
AND KCU1.CONSTRAINT_NAME = RC.CONSTRAINT_NAME
INNER JOIN INFORMATION_SCHEMA.KEY_COLUMN_USAGE AS KCU2
ON KCU2.CONSTRAINT_CATALOG = RC.UNIQUE_CONSTRAINT_CATALOG
AND KCU2.CONSTRAINT_SCHEMA = RC.UNIQUE_CONSTRAINT_SCHEMA
AND KCU2.CONSTRAINT_NAME = RC.UNIQUE_CONSTRAINT_NAME
AND KCU2.ORDINAL_POSITION = KCU1.ORDINAL_POSITION
One more thing:
Always create your scripts so you can run it N times if necessary.
So either drop the foreign key before you create it, or only create it if it doesn't exist. The same thing goes for the tables (don't drop them if they contain data).
Additionally, if you create a foreign key, you should check if all referenced tables exists, plus check that the referenced table has the primary key set.
Edit:
One tip, on a quick glare:
I would check if you really need DATETIME.
If you only need a date, use date instead of datetime.

That is how you do a FK but that data design does not look correct. You don't have an order point to a drug AND a drug point to an order. Read up on 3NF. A supplier does not have a single drug. DrugsID may have an S but it is still singular. This data design is not correct.

Related

How to use constraints to force two child items be from the same parent?

I have a Jobs table that holds jobs.
I have a Tasks table that holds tasks that belong to a job (1:many).
I have a Task_Relationships table that holds the data about which tasks depend on other tasks within a job.
I have 2 jobs, each job has 3 tasks and within the jobs the tasks are related as in the diagram. The Task_Relationships table is to represent that tasks within a job have dependencies between them.
How to ensure that when I add an entry to the Task_Relationships table say (1,2) representing the fact that task 1 is related to task 2, that tasks 1 and 2 are in the same job? I'm trying to enforce this through keys and not through code.
drop table if exists dbo.test_jobs
create table dbo.test_jobs (
[Id] int identity(1,1) primary key not null,
[Name] varchar(128) not null
)
drop table if exists dbo.test_tasks
create table dbo.test_tasks (
[Id] int identity(1,1) primary key not null,
[Job_Id] int not null,
[Name] varchar(128) not null
constraint fk_jobs foreign key ([Id]) references dbo.test_jobs(Id)
)
drop table if exists dbo.test_task_relationships
create table dbo.test_task_relationships (
[Id] int identity(1,1) not null,
[From_Task] int not null,
[To_Task] int not null
constraint fk_tasks_from foreign key ([From_Task]) references dbo.test_tasks(Id),
constraint fk_tasks_to foreign key ([To_Task]) references dbo.test_tasks(Id)
)
A reliance on identity columns as primary keys is not helping you here. And it is a logic fault to use an identity column in the relationship table IMO. Surely you do not intend to allow multiple rows to exist in that table with the same values for <from_task, to_task>.
Imagine the child table defined as:
create table dbo.test_tasks (
Job_Id int not null,
Task_Id tinyint not null,
Name varchar(128) not null,
constraint pk_tasks primary key clustered (Job_Id, Task_Id),
constraint fk_jobs foreign key ([Job_Id]) references dbo.test_jobs(Id)
);
Now your relationship table can be transformed into:
create table dbo.test_task_relationships (
From_Job int not null,
From_Task tinyint not null,
To_Job int not null,
To_Task tinyint not null
);
I'll leave it to you to complete the DDL but that should make your goal trivial.
You can declare a superkey in the Task table that includes the Job_Id column as well as columns from an existing key.
create table dbo.test_tasks (
[Id] int identity(1,1) primary key not null,
[Job_Id] int not null,
[Name] varchar(128) not null
constraint fk_jobs foreign key ([Id]) references dbo.test_jobs(Id),
constraint UQ_Tasks_WithJob UNIQUE (Id, Job_Id)
)
You can then add the Job_Id column to the relationships table and include it in both foreign key constraints:
create table dbo.test_task_relationships (
[Id] int identity(1,1) not null,
[From_Task] int not null,
Job_Id int not null,
[To_Task] int not null
constraint fk_tasks_from foreign key ([From_Task], Job_Id) references dbo.test_tasks(Id, Job_Id),
constraint fk_tasks_to foreign key ([To_Task], Job_Id) references dbo.test_tasks(Id, Job_Id)
)
There is now no way for the table to contain mismatched tasks. If necessary, wrap this table in a view/trigger if you don't want to expose the presence of the job_id column to applications and to automatically populate it during insert.

Add a referential constraint with a constant value

I have a table of locations:
CREATE TABLE [dbo].[loca_location] (
[loca_id] [int] NOT NULL IDENTITY,
[loca_name] [nvarchar](100) NOT NULL,
[loca_address_line_1] [nvarchar](100),
[loca_address_line_2] [nvarchar](100),
[loca_address_line_3] [nvarchar](100),
[loca_address_town] [nvarchar](100),
[loca_address_county] [nvarchar](100),
[loca_post_code] [nvarchar](12),
[loca_active] [bit] NOT NULL,
[loca_created] [datetimeoffset](0) NOT NULL,
[loca_created_by] [nvarchar](50) NOT NULL,
[loca_modified] [datetimeoffset](0) NOT NULL,
[loca_modified_by] [nvarchar](50) NOT NULL,
[loca_deleted] [datetimeoffset](0),
[loca_deleted_by] [nvarchar](50),
[loca_type] [char](1),
CONSTRAINT [PK_dbo.loca_store] PRIMARY KEY ([loca_id])
)
Now some locations may be my own, others may be customers. If customer, then loca_type will be C. If I own it, it will be L. If its a supplier, then it will be S.
Now a contract should always belong to a customer, so I want to make it so the loca_type = C is a constraint as well as the loca_id.
ALTER TABLE [dbo].[cont_contract] ADD CONSTRAINT [FK_dbo.cont_contract_dbo.loca_location_cust_id] FOREIGN KEY ([loca_id_customer]) REFERENCES [dbo].[loca_location] ([loca_id], `C`)
That doesn't work. Is it possible to do what I want?
This may work
1.Declare UNIQUE ([loca_id], [loca_type] ) on [loca_location] table. That is correct as any superset of PK is unique.
2.Add constant column to [cont_contract] table.
3.Create FK.
CREATE TABLE [dbo].[loca_location] (
[loca_id] [int] NOT NULL IDENTITY,
--..
[loca_type] [char](1) CHECK ([loca_type] IN ('A','B','C')), -- change as needed
CONSTRAINT [PK_dbo.loca_store] PRIMARY KEY ([loca_id])
)
ALTER TABLE [dbo].[loca_location] ADD CONSTRAINT [u1] UNIQUE ([loca_id],[loca_type]);
CREATE TABLE [dbo].[cont_contract] (
[id] [int] NOT NULL IDENTITY,
--..
[loca_id_customer] Int,
-- Constant column
[loca_type] [char](1) DEFAULT 'C' CHECK ([loca_type] ='C')
);
ALTER TABLE [dbo].[cont_contract] ADD CONSTRAINT [FK_dbo.cont_contract_dbo.loca_location_cust_id]
FOREIGN KEY ([loca_id_customer],[loca_type]) REFERENCES [dbo].[loca_location] ([loca_id], [loca_type]);

Composite Keys and Referential Integrity in T-SQL

Is it possible, in T-SQL, to have a relationship table with a composite key composed of 1 column defining Table Type and another column defining the Id of a row from a table referenced in the Table Type column?
For a shared-email address example:Three different user tables (UserA, UserB, UserC)One UserType Table (UserType)One Email Table (EmailAddress)One Email-User Relationship Table (EmailRelationship)The EmailRelationship Table contains three columns, EmailId, UserTypeId and UserId
Can I have a relationship from each User table to the EmailRelationship table (or some other way?) to maintain referential integrity?
I've tried making all three columns in the EmailRelationship table into primary keys, I've tried making only UserTypeId and UserId primary.
CREATE TABLE [dbo].[UserType](
[Id] [int] IDENTITY(1,1) NOT NULL ,
[Type] [varchar](50) NOT NULL)
insert into [dbo].[UserType]
([Type])
values
('A'),('B'),('C')
CREATE TABLE [dbo].[UserA](
[Id] [int] IDENTITY(1,1) NOT NULL,
[UserTypeId] [int] NOT NULL,
[Name] [varchar](50) NOT NULL)
insert into [dbo].[UserA]
(UserTypeId,Name)
values
(1,'UserA')
CREATE TABLE [dbo].[UserB](
[Id] [int] IDENTITY(1,1) NOT NULL,
[UserTypeId] [int] NOT NULL,
[Name] [varchar](50) NOT NULL)
insert into [dbo].[UserB]
(UserTypeId,Name)
values
(2,'UserB')
CREATE TABLE [dbo].[UserC](
[Id] [int] IDENTITY(1,1) NOT NULL,
[UserTypeId] [int] NOT NULL,
[Name] [varchar](50) NOT NULL)
insert into [dbo].[UserC]
(UserTypeId,Name)
values
(3,'UserC')
CREATE TABLE [dbo].[Email](
[Id] [int] IDENTITY(1,1) NOT NULL,
[EmailAddress] [varchar](50) NOT NULL)
insert into [dbo].[email]
(EmailAddress)
values
('SharedEmail#SharedEmail.com')
CREATE TABLE [dbo].[EmailRelationship](
[EmailId] [int] NOT NULL,
[UserTypeId] [int] NOT NULL,
[UserId] [int] NOT NULL)
insert into [dbo].[EmailRelationship]
(EmailId, UserTypeId, UserId)
values
(1,1,1),(1,2,1),(1,3,1)
No there isn't, a foreign key can refer to one table, and one table only, I can think of three ways you could approach this.
The first is to have 3 columns, one for each user table, each column with a foreign key, and a check constraint to check that at one, and only one of the values is not null
CREATE TABLE dbo.EmailRelationship
(
EmailId INT NOT NULL,
UserTypeId INT NOT NULL,
UserAId INT NULL,
UserBId INT NULL,
UserCId INT NULL,
CONSTRAINT FK_EmailRelationship__UserAID FOREIGN KEY (UserAId)
REFERENCES dbo.UserA (Id),
CONSTRAINT FK_EmailRelationship__UserBID FOREIGN KEY (UserBId)
REFERENCES dbo.UserB (Id),
CONSTRAINT FK_EmailRelationship__UserCID FOREIGN KEY (UserCId)
REFERENCES dbo.UserC (Id),
CONSTRAINT CK_EmailRelationship__ValidUserId CHECK
(CASE WHEN UserTypeID = 1 AND UserAId IS NOT NULL AND ISNULL(UserBId, UserCId) IS NULL THEN 1
WHEN UserTypeID = 2 AND UserBId IS NOT NULL AND ISNULL(UserAId, UserCId) IS NULL THEN 1
WHEN UserTypeID = 3 AND UserCId IS NOT NULL AND ISNULL(UserAId, UserBId) IS NULL THEN 1
ELSE 0
END = 1)
);
Then as a quick example trying to insert a UserAId with a user Type ID of 2 gives you an error:
INSERT EmailRelationship (EmailID, UserTypeID, UserAId)
VALUES (1, 1, 1);
The INSERT statement conflicted with the CHECK constraint "CK_EmailRelationship__ValidUserId".
The second approach is to just have a single user table, and store user type against it, along with any other common attributes
CREATE TABLE dbo.[User]
(
Id INT IDENTITY(1, 1) NOT NULL,
UserTypeID INT NOT NULL,
Name VARCHAR(50) NOT NULL,
CONSTRAINT PK_User__UserID PRIMARY KEY (Id),
CONSTRAINT FK_User__UserTypeID FOREIGN KEY (UserTypeID) REFERENCES dbo.UserType (UserTypeID),
CONSTRAINT UQ_User__Id_UserTypeID UNIQUE (Id, UserTypeID)
);
-- NOTE THE UNIQUE CONSTRAINT, THIS WILL BE USED LATER
Then you can just use a normal foreign key constraint on your email relationship table:
CREATE TABLE dbo.EmailRelationship
(
EmailId INT NOT NULL,
UserId INT NOT NULL,
CONSTRAINT PK_EmailRelationship PRIMARY KEY (EmailID),
CONSTRAINT FK_EmailRelationship__EmailId
FOREIGN KEY (EmailID) REFERENCES dbo.Email (Id),
CONSTRAINT FK_EmailRelationship__UserId
FOREIGN KEY (UserId) REFERENCES dbo.[User] (Id)
);
It is then no longer necessary to store UserTypeId against the email relationship because you can join back to User to get this.
Then, if for whatever reason you do need specific tables for different user types (this is not unheard of), you can create these tables, and enforce referential integrity to the user table:
CREATE TABLE dbo.UserA
(
UserID INT NOT NULL,
UserTypeID AS 1 PERSISTED,
SomeOtherCol VARCHAR(50),
CONSTRAINT PK_UserA__UserID PRIMARY KEY (UserID),
CONSTRAINT FK_UserA__UserID_UserTypeID FOREIGN KEY (UserID, UserTypeID)
REFERENCES dbo.[User] (Id, UserTypeID)
);
The foreign key from UserID and the computed column UserTypeID back to the User table, ensures that you can only enter users in this table where the UserTypeID is 1.
A third option is just to have a separate junction table for each User table:
CREATE TABLE dbo.UserAEmailRelationship
(
EmailId INT NOT NULL,
UserAId INT NOT NULL,
CONSTRAINT PK_UserAEmailRelationship PRIMARY KEY (EmailId, UserAId),
CONSTRAINT FK_UserAEmailRelationship__EmailId FOREIGN KEY (EmailId)
REFERENCES dbo.Email (Id),
CONSTRAINT FK_UserAEmailRelationship__UserAId FOREIGN KEY (UserAId)
REFERENCES dbo.UserA (Id)
);
CREATE TABLE dbo.UserBEmailRelationship
(
EmailId INT NOT NULL,
UserBId INT NOT NULL,
CONSTRAINT PK_UserBEmailRelationship PRIMARY KEY (EmailId, UserBId),
CONSTRAINT FK_UserBEmailRelationship__EmailId FOREIGN KEY (EmailId)
REFERENCES dbo.Email (Id),
CONSTRAINT FK_UserBEmailRelationship__UserBId FOREIGN KEY (UserBId)
REFERENCES dbo.UserB (Id)
);
Each approach has it's merits and drawbacks, so you would need to assess what is best for your scenario.
No it does not work that way. You cannot use a column value as a dynamic reference to different tables.
In general the data design is flawed.
Thanks to #GarethD I created a CHECK constraint that called a scalar-function that would enforce referential integrity (only upon insert, refer to caveat below):
Using my above example:
alter FUNCTION [dbo].[UserTableConstraint](#Id int, #UserTypeId int)
RETURNS int
AS
BEGIN
IF EXISTS (SELECT Id From [dbo].[UserA] WHERE Id = #Id and UserTypeId = #UserTypeId)
return 1
ELSE IF EXISTS (SELECT Id From [dbo].[UserB] WHERE Id = #Id and UserTypeId = #UserTypeId)
return 1
ELSE IF EXISTS (SELECT Id From [dbo].[UserC] WHERE Id = #Id and UserTypeId = #UserTypeId)
return 1
return 0
end;
alter table [dbo].[emailrelationship]
--drop constraint CK_UserType
with CHECK add constraint CK_UserType
CHECK([dbo].[UserTableConstraint](UserId,UserTypeId) = 1)
I am sure there is a not insignificant overhead to a Scalar-function call from within a CONSTRAINT. If the above becomes prohibitive I will report back here, though the tables in question will not have to deal with a large volume of INSERTs.
If there are any other reasons to not do the above, I would like to hear them. Thanks!
Update:
I've tested INSERT and UPDATE with 100k rows (SQL Server 2014, 2.1ghz quadcore w/ 8gb ram):
INSERT takes 2 seconds with out the CONSTRAINT
and 3 seconds with the CHECK CONSTRAINT
Turning on IO and TIME STATISTICS causes the INSERT tests to run in:
1.7 seconds with out the CONSTRAINT
and 10 seconds with the CHECK CONSTRAINT
I left the STATISTICS on for the UPDATE 100k rows test:
just over 1sec with out the CONSTRAINT
and 1.5sec with the CHECK CONSTRAINT
My referenced tables (UserA, UserB, UserC from my example) only contain around 10k rows each, so anybody else looking to implement the above may want to run some additional testing, especially if your referenced tables contain millions of rows.
Caveat:
The above solution may not be suitable for most uses, as the only time referential integrity is checked is during the CHECK CONSTRAINT upon INSERT. Any other operations or modifications of the data needs to take that into account. For example, using the above, if an Email is deleted any related EmailRelationship entries will be pointing to invalid data.

SQL Server doesn't understand USE <<DATABASE>>

I have a problem with my SQL code. When I try to use database DIGITECH, SQL Server says the database does not exist.
This is my code
create database DIGITECH;
Go
use DIGITECH;
/*Erstellen der Tabellen*/
create table produkt(
PID int identity(1,1) NOT NULL,
Produktname nvarchar(50) NULL,
Spezifikationen nvarchar(100) NULL,
Beschreibung nvarchar(200) NULL,
Preis int NOT NULL,
FK_HeID int NULL,
FK_KatID int NULL,
FK_StID int NULL
);
go
create table hersteller(
HeID int identity(1,1) NOT NULL,
Hersteller nvarchar(50) NOT NULL
);
go
create table kategorie(
KatID int identity(1,1) NOT NULL,
KategorieName nvarchar(20) NULL
);
go
create table stat_us(
StID int identity(1,1) NOT NULL,
Status nvarchar(20) NOT NULL
);
go
create table verbindungstabelle_produkt_order(
FK_OderID int NOT NULL,
FK_PID int NOT NULL
);
go
create table or_der(
OrderID int identity(1,1) NOT NULL,
Status char NOT NULL,
FK_Kunde int NULL
);
create table kunde(
KID int identity NOT NULL,
Name nvarchar(50) NULL,
Vorname nvarchar(50) NULL,
Email nvarchar(70) NULL,
Geschlecht char NULL,
FK_AdID int NULL
);
go
create table adresse(
AdID int identity(1,1) NOT NULL,
Strasse nvarchar(50) NULL,
Hausnummer int NULL,
FK_PLZ int NULL
);
go
create table plz(
PLZ int identity(1,1) NOT NULL,
Ort nvarchar(60) NOT NULL
);
go
/* Primärschlussel*/
alter table produkt
add constraint PK_produkt
primary key (PID);
go
alter table kategorie
add constraint PK_kategorie
primary key (KatID);
go
alter table stat_us
add constraint PK_status
primary key (StID);
go
alter table hersteller
add constraint PK_hersteller
primary key (HeID);
go
alter table or_der
add constraint PK_order
primary key (OrderID);
go
alter table kunde
add constraint PK_kunde
primary key (KID);
go
alter table adresse
add constraint PK_adresse
primary key (KID);
go
alter table plz
add constraint PK_plz
primary key (PLZ);
go
/* Fremdkeys hinzufügen */
alter table produkt
add constraint FK_kategorie
foreign key (FK_KatID)
references kategorie (KatID);
go
alter table produkt
add constraint FK_status
foreign key (FK_StID)
references stat_us (StID);
go
alter table produkt
add constraint FK_hersteller
foreign key (FK_HeID)
references hersteller (HeID);
go
alter table verbindungstabelle_produkt_order
add constraint FK_PID
foreign key (FK_PID)
references produkt (PID);
go
alter table verbindungstabelle_produkt_order
add constraint FK_OrderID
foreign key (FK_OrderID)
references ord_er (OrderID);
go
alter table ord_er
add constraint FK_JID
foreign key (FK_KID)
references kunde (KID);
go
alter table kunde
add constraint FK_AdID
foreign key (FK_AdID)
references adresse (AdID);
go
alter table adresse
add constraint FK_PLZ
foreign key (FK_PLZ)
references plz (PLZ);
go
It is important that the create database AND the use are in one document.
This is the full Code
create database DIGITECH;
Go
use DIGITECH;
/*Erstellen der Tabellen*/
create table produkt(
PID int identity(1,1) NOT NULL,
Produktname nvarchar(50) NULL,
Spezifikationen nvarchar(100) NULL,
Beschreibung nvarchar(200) NULL,
Preis int NOT NULL,
FK_HeID int NULL,
FK_KatID int NULL,
FK_StID int NULL
);
go
create table hersteller(
HeID int identity(1,1) NOT NULL,
Hersteller nvarchar(50) NOT NULL
);
go
create table kategorie(
KatID int identity(1,1) NOT NULL,
KategorieName nvarchar(20) NULL
);
go
create table stat_us(
StID int identity(1,1) NOT NULL,
Status nvarchar(20) NOT NULL
);
go
create table verbindungstabelle_produkt_order(
FK_OderID int NOT NULL,
FK_PID int NOT NULL
);
go
create table or_der(
OrderID int identity(1,1) NOT NULL,
Status char NOT NULL,
FK_Kunde int NULL
);
create table kunde(
KID int identity NOT NULL,
Name nvarchar(50) NULL,
Vorname nvarchar(50) NULL,
Email nvarchar(70) NULL,
Geschlecht char NULL,
FK_AdID int NULL
);
go
create table adresse(
AdID int identity(1,1) NOT NULL,
Strasse nvarchar(50) NULL,
Hausnummer int NULL,
FK_PLZ int NULL
);
go
create table plz(
PLZ int identity(1,1) NOT NULL,
Ort nvarchar(60) NOT NULL
);
go
/* Primärschlussel*/
alter table produkt
add constraint PK_produkt
primary key (PID);
go
alter table kategorie
add constraint PK_kategorie
primary key (KatID);
go
alter table stat_us
add constraint PK_status
primary key (StID);
go
alter table hersteller
add constraint PK_hersteller
primary key (HeID);
go
alter table or_der
add constraint PK_order
primary key (OrderID);
go
alter table kunde
add constraint PK_kunde
primary key (KID);
go
alter table adresse
add constraint PK_adresse
primary key (KID);
go
alter table plz
add constraint PK_plz
primary key (PLZ);
go
/* Fremdkeys hinzufügen */
alter table produkt
add constraint FK_kategorie
foreign key (FK_KatID)
references kategorie (KatID);
go
alter table produkt
add constraint FK_status
foreign key (FK_StID)
references stat_us (StID);
go
alter table produkt
add constraint FK_hersteller
foreign key (FK_HeID)
references hersteller (HeID);
go
alter table verbindungstabelle_produkt_order
add constraint FK_PID
foreign key (FK_PID)
references produkt (PID);
go
alter table verbindungstabelle_produkt_order
add constraint FK_OrderID
foreign key (FK_OrderID)
references ord_er (OrderID);
go
alter table ord_er
add constraint FK_JID
foreign key (FK_KID)
references kunde (KID);
go
alter table kunde
add constraint FK_AdID
foreign key (FK_AdID)
references adresse (AdID);
go
alter table adresse
add constraint FK_PLZ
foreign key (FK_PLZ)
references plz (PLZ);
go
Screenshot 1
You need to put a GO after your CREATE DATABASE statement. The GO command informs SSMS to separate the script into different batches, split on each GO. Since your attempt to select the database was in the same batch as creating it, it threw an error as it didn't yet exist at the time of execution.
create database DIGITECH;
Go
use DIGITECH;
/*Erstellen der Tabellen*/
create table produkt(
PID int identity(1,1) NOT NULL,
Produktname nvarchar(50) NULL,
Spezifikationen nvarchar(100) NULL,
Beschreibung nvarchar(200) NULL,
Preis int NOT NULL,
FK_HeID int NULL,
FK_KatID int NULL,
FK_StID int NULL
);
go
EDIT (New Information in Question)
You have three problems with your script:
...
alter table adresse
add constraint PK_adresse
primary key (AdID); -- This was changed from KID
go
...
You had the PRIMARY KEY set as KID, which isn't a column on the table.
...
alter table verbindungstabelle_produkt_order
add constraint FK_OrderID
foreign key (FK_OderID) -- Changed from FK_OrderID
references or_der (OrderID); -- Changed from ord_er
go
...
You had the FOREIGN KEY declared on FK_OrderID, which isn't a column on the table.
You are also trying to reference a table named ord_er, which doesn't exist.
Changing those to what they should be leaves us with one more error:
alter table or_der
add constraint FK_JID
foreign key (FK_Kunde) -- Changed from FK_KID
references kunde (KID);
go
All of this was easy to figure out by just running your script and reading the error messages...
FULL CORRECTED SCRIPT
create database DIGITECH;
Go
use DIGITECH;
/*Erstellen der Tabellen*/
create table produkt(
PID int identity(1,1) NOT NULL,
Produktname nvarchar(50) NULL,
Spezifikationen nvarchar(100) NULL,
Beschreibung nvarchar(200) NULL,
Preis int NOT NULL,
FK_HeID int NULL,
FK_KatID int NULL,
FK_StID int NULL
);
go
create table hersteller(
HeID int identity(1,1) NOT NULL,
Hersteller nvarchar(50) NOT NULL
);
go
create table kategorie(
KatID int identity(1,1) NOT NULL,
KategorieName nvarchar(20) NULL
);
go
create table stat_us(
StID int identity(1,1) NOT NULL,
Status nvarchar(20) NOT NULL
);
go
create table verbindungstabelle_produkt_order(
FK_OderID int NOT NULL,
FK_PID int NOT NULL
);
go
create table or_der(
OrderID int identity(1,1) NOT NULL,
Status char NOT NULL,
FK_Kunde int NULL
);
create table kunde(
KID int identity NOT NULL,
Name nvarchar(50) NULL,
Vorname nvarchar(50) NULL,
Email nvarchar(70) NULL,
Geschlecht char NULL,
FK_AdID int NULL
);
go
create table adresse(
AdID int identity(1,1) NOT NULL,
Strasse nvarchar(50) NULL,
Hausnummer int NULL,
FK_PLZ int NULL
);
go
create table plz(
PLZ int identity(1,1) NOT NULL,
Ort nvarchar(60) NOT NULL
);
go
/* Primärschlussel*/
alter table produkt
add constraint PK_produkt
primary key (PID);
go
alter table kategorie
add constraint PK_kategorie
primary key (KatID);
go
alter table stat_us
add constraint PK_status
primary key (StID);
go
alter table hersteller
add constraint PK_hersteller
primary key (HeID);
go
alter table or_der
add constraint PK_order
primary key (OrderID);
go
alter table kunde
add constraint PK_kunde
primary key (KID);
go
alter table adresse
add constraint PK_adresse
primary key (AdID); -- This was changed from KID
go
alter table plz
add constraint PK_plz
primary key (PLZ);
go
/* Fremdkeys hinzufügen */
alter table produkt
add constraint FK_kategorie
foreign key (FK_KatID)
references kategorie (KatID);
go
alter table produkt
add constraint FK_status
foreign key (FK_StID)
references stat_us (StID);
go
alter table produkt
add constraint FK_hersteller
foreign key (FK_HeID)
references hersteller (HeID);
go
alter table verbindungstabelle_produkt_order
add constraint FK_PID
foreign key (FK_PID)
references produkt (PID);
go
alter table verbindungstabelle_produkt_order
add constraint FK_OrderID
foreign key (FK_OderID) -- Changed from FK_OrderID
references or_der (OrderID);
go
alter table or_der
add constraint FK_JID
foreign key (FK_Kunde) -- Changed from FK_KID
references kunde (KID);
go
alter table kunde
add constraint FK_AdID
foreign key (FK_AdID)
references adresse (AdID);
go
alter table adresse
add constraint FK_PLZ
foreign key (FK_PLZ)
references plz (PLZ);
go
You got error because you cant execute all statements in same batch.You have to seperate them.Go Command is used to segregate batches..Here are some interesting rules
CREATE DEFAULT, CREATE FUNCTION, CREATE PROCEDURE, CREATE RULE, CREATE TRIGGER, and CREATE VIEW statements cannot be combined with other statements in a batch.
A table cannot be altered and then the new columns referenced in the same batch.
So if you do any of the above operations,then they must be seperated by GO
References:
In SQL Server, when should you use GO and when should you use semi-colon ;?
https://technet.microsoft.com/en-us/library/aa172435%28SQL.80%29.aspx
Please add your "full code" into your question (via edit option) and delete your answer, as this is no answer...
Your code is full of typos and errors:
ord_er or or_der?
No FK_OderID column (should be FK_OrderID?)
You create an FK to or_der on a column FK_KID, which does not exist...
???
Please clean your script and try again...

Error Defining Foreign Key

I have the following two database tables defined:
CREATE TABLE [dbo].[Classrooms] (
[ID] INT IDENTITY (1, 1) NOT NULL,
[SystemAccount_ID] INT NOT NULL,
[ClassroomName] VARCHAR (30) NOT NULL,
CONSTRAINT [PK_Table] PRIMARY KEY CLUSTERED ([ID]),
CONSTRAINT [FK_Classrooms_SystemAccount] FOREIGN KEY ([SystemAccount_ID]) REFERENCES [dbo].[SystemAccounts] ([ID])
);
CREATE TABLE [dbo].[Students] (
[ID] INT IDENTITY (1, 1) NOT NULL,
[SystemAccount_ID] INT NOT NULL,
[Classroom_ID] INT NULL,
[PhotoID] INT NULL,
[FirstName] VARCHAR (20) NOT NULL,
[LastName] VARCHAR (40) NOT NULL,
[NewsTemplate] TINYINT NOT NULL,
CONSTRAINT [PK_Students] PRIMARY KEY CLUSTERED ([ID] ASC),
CONSTRAINT [FK_Students_Classrooms] FOREIGN KEY ([Classroom_ID]) REFERENCES [dbo].[Classrooms] ([ID]),
CONSTRAINT [FK_Students_SystemAccounts] FOREIGN KEY ([SystemAccount_ID]) REFERENCES [dbo].[SystemAccounts] ([ID])
);
Data model details:
Students belong to zero or one classroom via Classroom_ID FK
Students belong to one System Account via SystemAccount_ID FK
Classrooms belong to one System Account via SystemAccount_ID FK (implying a system account can have zero or more Classrooms)
What I'm attempting to do is enforce when students are added to a classroom (by setting the Classroom_ID key in the Students table) that the classroom belongs to the same system account as the student. I could easily enforce this at the business logic layer but then I'd be requiring every programmer to remember to do this. So ideally, I'd be able to do this at the data layer as a constraint.
I tried adding a FK constraint to the Students table:
CONSTRAINT [FK_Students_ToTable] FOREIGN KEY ([SystemAccount_ID]) REFERENCES [Classrooms]([SystemAccount_ID])
Which results in the following error compliments of SQL Server:
Update cannot proceed due to validation errors.
Please correct the following errors and try again.
SQL71516 :: The referenced table '[dbo].[Classrooms]' contains no primary or candidate keys that match the referencing column list in the foreign key. If the referenced column is a computed column, it should be persisted.
I've tried a few different things but my SQL mojo isn't powerful enough to hack past this one. Any help would be greatly appreciated.
Add a UNIQUE constraint on the combination of the two columns in Classrooms:
CREATE TABLE [dbo].[Classrooms] (
[ID] INT IDENTITY (1, 1) NOT NULL,
[SystemAccount_ID] INT NOT NULL,
[ClassroomName] VARCHAR (30) NOT NULL,
CONSTRAINT [PK_Table]
PRIMARY KEY CLUSTERED ([ID]),
CONSTRAINT [FK_Classrooms_SystemAccount]
FOREIGN KEY ([SystemAccount_ID])
REFERENCES [dbo].[SystemAccounts] ([ID]),
CONSTRAINT [UQ_Classrooms_ID_SystemAccount_ID]
UNIQUE ([SystemAccount_ID], [ID])
);
Then, in the Students table, combine the two FOREIGN KEY constraints into one, or in your case (because Classroom_ID isnullable), change the FK to Classroom to use the combination of the two columns:
CREATE TABLE [dbo].[Students] (
[ID] INT IDENTITY (1, 1) NOT NULL,
[SystemAccount_ID] INT NOT NULL,
[Classroom_ID] INT NULL,
[PhotoID] INT NULL,
[FirstName] VARCHAR (20) NOT NULL,
[LastName] VARCHAR (40) NOT NULL,
[NewsTemplate] TINYINT NOT NULL,
CONSTRAINT [PK_Students]
PRIMARY KEY CLUSTERED ([ID] ASC),
CONSTRAINT [FK_Students_Classrooms]
FOREIGN KEY ([SystemAccount_ID], [Classroom_ID])
REFERENCES [dbo].[Classrooms] ([SystemAccount_ID], [ID]),
CONSTRAINT [FK_Students_SystemAccounts] -- this wouldn't be needed if
FOREIGN KEY ([SystemAccount_ID]) -- Classrooms_ID was NOT NULL
REFERENCES [dbo].[SystemAccounts] ([ID])
);