Change column to foreign key - sql

How do I change an existing column from bit to a foreign key (int)?
For example, column NEW_B was created like this:
ALTER TABLE [dbo].[APPLICATION]
ADD [NEW_B] [bit] NULL
GO
But now I want the NEW_B to reference column ID (int) of table ATTACHMENT (want to keep the name NEW_B, also allow NULLs).

Here is the syntax:
--alter existing column to int
ALTER TABLE [dbo].[APPLICATION] ALTER COLUMN [NEW_B] INT NULL
GO
--add foreign key constraint
ALTER TABLE [dbo].[APPLICATION] WITH CHECK ADD CONSTRAINT [FK_APPLICATION_ATTACHMENT] FOREIGN KEY([NEW_B])
REFERENCES [dbo].[ATTACHMENT] ([ID])
GO
ALTER TABLE [dbo].[APPLICATION] CHECK CONSTRAINT [FK_APPLICATION_ATTACHMENT]
GO

Related

Database contains foreign key that doesn exist even though there is a foreign key constraint?

I am working with a database where there is a foreign key ID that doesn't exist even though there is a foreign key constraint.
There is a table called "Workplace" with a foreign key column called "AddressID" pointing to another table called "Address"
The foreign key is as follows:
ALTER TABLE [dbo].[Workplace] WITH NOCHECK ADD CONSTRAINT [FK_Workplace_Address] FOREIGN KEY([AddressID])
REFERENCES [dbo].[Address] ([ID])
GO
ALTER TABLE [dbo].[Workplace] CHECK CONSTRAINT [FK_Workplace_Address]
GO
For one particular row in the Workplace table, the AddressID has a value of "1".
When I run select * from Address where ID = 1 there is no result.
Then I ran update Workplace set AddressID = 3 where Workplace.ID = 20 the value changed to 3 and I have verified that an Address with ID 3 exists.
Then I ran update Workplace set AddressID = 1 where Workplace.ID = 20 again and I get the error
The UPDATE statement conflicted with the FOREIGN KEY constraint "FK_Workplace_Address". The conflict occurred in database db_name, table "dbo.Address", column 'ID'.
I don't understand how the value 1 could have been put there in the first place. The Address with ID=1 couldn't have been deleted after the constraint was put in place. The constraint creation would also fail if the record was deleted in the first place. Does anyone know how this could be possible?
This is a database on Windows Server 2016, SQL Server 12.0.4237.0
You create your FOREIGN KEY with NOCHECK, as a result the values that already exist in the table are not checked. This can be replicated with the following:
CREATE TABLE dbo.Address (ID int NOT NULL CONSTRAINT PK_Address PRIMARY KEY);
GO
CREATE TABLE dbo.Workplace (ID int NOT NULL CONSTRAINT PK_Workplace PRIMARY KEY,
AddressID int)
GO
INSERT INTO dbo.Workplace
VALUES(1,3); --Works
GO
ALTER TABLE dbo.WorkPlace WITH NOCHECK ADD CONSTRAINT FK_Workplace_Address FOREIGN KEY (AddressID) REFERENCES dbo.Address(ID);
GO
ALTER TABLE dbo.Workplace CHECK CONSTRAINT FK_Workplace_Address;
GO
INSERT INTO dbo.Workplace
VALUES(2,3); --Fails
GO
UPDATE dbo.Workplace
SET AddressID = 2
WHERE ID = 1; --Fails
GO
DROP TABLE dbo.Workplace;
DROP TABLE dbo.Address;
As you can see, only rows that are INSERTed or UPDATEd after the constraint was created (with NOCHECK) are validated; the first row INSERTed is left as it was, with a reference to a row that does not exist.
Instead, create the key without NOCHECK defined, or with CHECK, and the statement will fail when you try to create it:
CREATE TABLE dbo.Address (ID int NOT NULL CONSTRAINT PK_Address PRIMARY KEY);
GO
CREATE TABLE dbo.Workplace (ID int NOT NULL CONSTRAINT PK_Workplace PRIMARY KEY,
AddressID int)
GO
INSERT INTO dbo.Workplace
VALUES(1,3); --Works
GO
ALTER TABLE dbo.WorkPlace WITH CHECK ADD CONSTRAINT FK_Workplace_Address FOREIGN KEY (AddressID) REFERENCES dbo.Address(ID); --Fails
GO
DROP TABLE dbo.Workplace;
DROP TABLE dbo.Address;
This generates the error below:
The ALTER TABLE statement conflicted with the FOREIGN KEY constraint "FK_Workplace_Address". The conflict occurred in database "Sandbox", table "dbo.Address", column 'ID'.
Alternatively, create the key when you create the tables; though it's likely too late for that now.
CREATE TABLE dbo.Address (ID int NOT NULL CONSTRAINT PK_Address PRIMARY KEY);
GO
CREATE TABLE dbo.Workplace (ID int NOT NULL CONSTRAINT PK_Workplace PRIMARY KEY,
AddressID int CONSTRAINT FK_Workplace_Address FOREIGN KEY REFERENCES dbo.Address(ID));
GO
INSERT INTO dbo.Workplace
VALUES(1,3); --Fails
GO
DROP TABLE dbo.Workplace;
DROP TABLE dbo.Address;

How to add multiple foreign keys with nocheck for each one?

i need to create multiple fk for diffrent fields with nocheck for each fk,
all the examples i see is only for 1 fk at a time,
i need something like this :
ALTER TABLE contact
WITH NOCHECK ADD CONSTRAINT [FK_check5]
FOREIGN KEY (accountid) REFERENCES dbo.account ([accountid]),
WITH NOCHECK ADD CONSTRAINT [FK_check6]
FOREIGN KEY (roleid) REFERENCES dbo.role ([id])
the disabled must be on the create level and not after it
seperate your alter table statement into two
ALTER TABLE contact
WITH NOCHECK ADD CONSTRAINT [FK_check5]
FOREIGN KEY (accountid) REFERENCES dbo.account ([accountid]);
ALTER TABLE CONTACTS
WITH NOCHECK ADD CONSTRAINT [FK_check6]
FOREIGN KEY (roleid) REFERENCES dbo.role ([id]);
The 'NoCheck' will apply to all the constraints you add in the statement, you don't need to repeat it:
Example below (tested in SQL 2012):
CREATE TABLE account (accountid int, PRIMARY KEY (accountid))
GO
CREATE TABLE [role] (id int, PRIMARY KEY (id))
GO
CREATE TABLE contact (accountid int, roleid int)
GO
insert into contact values (1,1)
GO
ALTER TABLE contact
WITH NOCHECK
ADD
CONSTRAINT [FK_check5] FOREIGN KEY (accountid) REFERENCES [account] ([accountid])
,CONSTRAINT [FK_check6] FOREIGN KEY (roleid) REFERENCES [role] ([id])
If your intention is to only have the foreign key for ER diagramming, you can turn off enforcing of the constraint. See the below article for more information.
https://learn.microsoft.com/en-us/sql/relational-databases/tables/disable-foreign-key-constraints-with-insert-and-update-statements
as per the example provided in the article:
USE AdventureWorks2012;
GO
ALTER TABLE Purchasing.PurchaseOrderHeader
NOCHECK CONSTRAINT FK_PurchaseOrderHeader_Employee_EmployeeID;
GO
That being said, I would recommend that you NEVER do this in a production system on an ongoing basis. Foreign key constraints exist for a reason, to maintain data integrity. If you are inserting data in a way that violates foreign key constraints you may want to review your data design.

Alter a table to add a foreign key constraint with a default value

How do I alter a table to have a column a foreign key constraint with a default value?
In T-SQL if you're using SQL-Server, just be careful to put a real key for default.
Edit: As said in the comments, be careful that you really need a default value for a foreign key, there could be a design problem.
ALTER TABLE [tablename]
ADD CONSTRAINT [CK_columnname_default]
DEFAULT [your_default_value] FOR [columnname];
GO
ALTER TABLE [tablename]
ADD CONSTRAINT [FK_nameForeignKey] FOREIGN KEY (columnname)
REFERENCES [dbo].[oTable] (oTableID)
ON UPDATE CASCADE;
GO
Well I did the following and it worked for me:
ALTER TABLE Employee
ADD RegionID varchar(3)
CONSTRAINT [Default_Value_Region] default ('US') NOT NULL,
CONSTRAINT [FK_EMPLOYEE_Region] FOREIGN KEY([RegionID])
REFERENCES [dbo].[Region] ([Code])
GO

Table A's PK is being referenced by Table B's FK. Cannot drop Table A's PK

MS SQL Server
I'm making a star schema. I've set the PK's and FK for my tables and am now trying to write a procedure that will drop the constraints, truncate the tables, add the constraints again, and then repopulate the tables. When I try to drop the constraints I receive the error:
"The constraint PK_TIMEDIM is being referenced by table SalesFactTable, foreign key constraint FK_SALESFACTTABLE. Could not drop constraint."
EDIT: One problem solved. Another found. I receive the same error except now there are mysterious, auto-generated FK's such as FK__SalesFact__CUST___19DFD96B.
Please show me what I'm doing wrong.
ALTER PROCEDURE [dbo].[A11]
AS
BEGIN
--Drop constraints
ALTER TABLE SalesFactTable
DROP CONSTRAINT FK_SALESFACTTABLE
ALTER TABLE SalesFactTable
DROP CONSTRAINT PK_SALESFACTTABLE
ALTER TABLE TimeDim
DROP CONSTRAINT PK_TIMEDIM
ALTER TABLE CustomerDim
DROP CONSTRAINT PK_CUSTOMERDIM
ALTER TABLE PartDim
DROP CONSTRAINT PK_PARTDIM
--Truncate tables
TRUNCATE TABLE TimeDim
TRUNCATE TABLE CustomerDim
TRUNCATE TABLE PartDim
TRUNCATE TABLE SalesFactTable
--Add constraints
ALTER TABLE TimeDim
ADD CONSTRAINT PK_TIMEDIM PRIMARY KEY (TIME_ID)
ALTER TABLE CustomerDim
ADD CONSTRAINT PK_CUSTOMERDIM PRIMARY KEY (CUST_ID)
ALTER TABLE PartDim
ADD CONSTRAINT PK_PARTDIM PRIMARY KEY (PART_ID)
ALTER TABLE SalesFactTable
ADD CONSTRAINT FK_SALESFACTTABLE FOREIGN KEY (TIME_ID) REFERENCES TimeDim (TIME_ID),
FOREIGN KEY (CUST_ID) REFERENCES CustomerDim (CUST_ID),
FOREIGN KEY (PART_ID) REFERENCES PartDim (PART_ID)
ALTER TABLE SalesFactTable
ADD CONSTRAINT PK_SALESFACTTABLE PRIMARY KEY (TIME_ID, CUST_ID, PART_ID)
**Foreign keys are referenced by the Primary key, so you are not allowed to remove the primary key before removing the Foreign Key constraint.
so, you need to remove the foreign key first to remove the Primary key constraint from a table.
**
ALTER PROCEDURE [dbo].[A11]
AS
BEGIN
--Drop FK constraints
ALTER TABLE SalesFactTable
DROP CONSTRAINT FK_SALESFACTTABLE
--Drop PK constraints
ALTER TABLE SalesFactTable
DROP CONSTRAINT PK_SALESFACTTABLE
ALTER TABLE TimeDim
DROP CONSTRAINT PK_TIMEDIM
ALTER TABLE CustomerDim
DROP CONSTRAINT PK_CUSTOMERDIM
ALTER TABLE PartDim
DROP CONSTRAINT PK_PARTDIM
--Truncate tables
TRUNCATE TABLE TimeDim
TRUNCATE TABLE CustomerDim
TRUNCATE TABLE PartDim
TRUNCATE TABLE SalesFactTable
--Add constraints
ALTER TABLE TimeDim
ADD CONSTRAINT PK_TIMEDIM PRIMARY KEY (TIME_ID)
ALTER TABLE CustomerDim
ADD CONSTRAINT PK_CUSTOMERDIM PRIMARY KEY (CUST_ID)
ALTER TABLE PartDim
ADD CONSTRAINT PK_PARTDIM PRIMARY KEY (PART_ID)
ALTER TABLE SalesFactTable
ADD CONSTRAINT FK_SALESFACTTABLE FOREIGN KEY (TIME_ID) REFERENCES TimeDim (TIME_ID),
FOREIGN KEY (CUST_ID) REFERENCES CustomerDim (CUST_ID),
FOREIGN KEY (PART_ID) REFERENCES PartDim (PART_ID)
ALTER TABLE SalesFactTable
ADD CONSTRAINT PK_SALESFACTTABLE PRIMARY KEY (TIME_ID, CUST_ID, PART_ID)

Alter Table Add Column with Default value And FK, that Value no existing in FK Reference Data

This is My Tables :
Member : Id, ....
Product: Id, ....
My Member Table have some values none if them with Id = 0 and I don't want to add any member with Id = 0, So I try to run this Script:
ALTER TABLE [Product]
ADD [Member_Id] BIGINT NOT NULL DEFAULT(0),
CONSTRAINT [FK_Product_Member] FOREIGN KEY ([Member_Id]) REFERENCES [Member];
So There is an Error :
The ALTER TABLE statement conflicted with the FOREIGN KEY constraint "FK_Product_Member".
So I try this one:
SET IDENTITY_INSERT [Member] ON
INSERT INTO [Member] ([Id]) VALUES (0);
SET IDENTITY_INSERT [Member] OFF
ALTER TABLE [Product]
ADD [Member_Id] BIGINT NOT NULL DEFAULT(0),
CONSTRAINT [FK_Product_Member] FOREIGN KEY ([Member_Id]) REFERENCES [Member];
DELETE FROM [Member] WHERE [Member].[Id] = 0;
Then The new Error is:
The DELETE statement conflicted with the REFERENCE constraint "FK_Product_Member".
If I try to create all Tables again, every thing will be OK of course with lost my Data so need to get backup, create tables and restore data. So Is there any way to alter Table with this situation? what is your suggestion?
The only "value" that you can have in a referencing table, such that the foreign key constraint is not enforced, is NULL. Not 0, or any other magic value.
So the obvious solution is to allow NULLs:
ALTER TABLE [Product]
ADD [Member_Id] BIGINT NULL,
CONSTRAINT [FK_Product_Member] FOREIGN KEY ([Member_Id]) REFERENCES [Member];
your "alter table" is the better way to do this.but at first you are adding the table with value "0" and this is "FOREIGN KEY" but you have not a Member with value "0" so you get error.
the best way as a know is .alter table and then make the true value to the new column and then alter the column and set that to the "FOREIGN KEY"