How do I modify this SQL schema to constrain data in tables? - sql-server

Newbie in need of help.
I'm creating a small database.
I want to constrain data in a couple of tables - Lender and Pingtree. The ProviderType table contains lookup data and contains either 'Lender' or 'Pingtree'. How can I modify this structure so that the Lender table only can contain Lender types and Pingtree, Pingtree types?

Guessing that ProviderTypeID is the column in the Provider table that distinguishes between the two types, then you must add this same column to both the Lender and Pingtree tables, add a suitable key (if it doesn't already exist) in Provider on ID, ProviderTypeId, and then add a composite FOREIGN KEY constraint to the Lender and Pingtree tables that include these columns.
While this may sound like a drag, it is a known pattern called supertyping/subtyping. When the supertype (Provider) can be multiple subtypes, you don't need the TypeId column. But when the subtypes are mutually exclusive, this is what you must do.
It might look something like this:
ALTER TABLE dbo.Lender ADD ProviderTypeId tinyint NOT NULL
CONSTRAINT DF_Lender_ProviderTypeID DEFAULT (1)
CONSTRAINT CK_Lender_ProviderTypeID_Is_Lender CHECK (ProviderTypeID = 1);
ALTER TABLE dbo.Pingtree ADD ProviderTypeId tinyint NOT NULL
CONSTRAINT DF_Pingtree_ProviderTypeID DEFAULT (2)
CONSTRAINT CK_Pingtree_ProviderTypeID_Is_Pingtree CHECK (ProviderTypeID = 2);
-- Any of a PK, UNIQUE constraint, or unique index will do
ALTER TABLE dbo.Provider ADD CONSTRAINT UQ_Provider_ID_ProviderTypeID
UNIQUE (ID, ProviderTypeID);
ALTER TABLE dbo.Lender DROP CONSTRAINT FK_Lender_ProviderId;
ALTER TABLE dbo.Lender ADD CONSTRAINT FK_Lender_ProviderId_ProviderTypeId
FOREIGN KEY (ID, ProviderTypeID) REFERENCES dbo.Provider (ID, ProviderTypeID);
ALTER TABLE dbo.PingTree DROP CONSTRAINT FK_PingTree_ProviderId;
ALTER TABLE dbo.PingTree ADD CONSTRAINT FK_PingTree_ProviderId_ProviderTypeId
FOREIGN KEY (ID, ProviderTypeID) REFERENCES dbo.Provider (ID, ProviderTypeID);
If written correctly (specifying the column list on INSERT) your stored procedures and application SQL code should not have to change.

Related

Table with multiple relations to a single primary key

Is it possible to create multiple relations from one table, to another table?
I have a table containing purchases, each of these purchases have a origin_country and a destination_country.
I would like to have relations (as foreign keys) to a single PK on a table from these two columns from the same table.
i have tried the following queries:
alter table Purchases
add constraint FK_Purchases_OriginCountries
foreign key (FK_OriginCountryCode) references dbo.countries
go
alter table Purchases
add constraint FK_Purchases_DestinationCountries
foreign key (FK_DestinationCountryCode) references dbo.countries
go
But end up getting a conflict, I can't however find documentation that this is not possible...
[23000][547] The ALTER TABLE statement conflicted with the FOREIGN KEY
constraint "FK_Purchases_DestinationCountries". The conflict occurred
in database "Market", table "dbo.countries", column 'ID'.
Is this relationship intentionally not possible, or did i just make a mistake?
Thank you
Yes you can.
The error is not a result of trying to create two foreign keys back to a single table, that's perfectly fine. Try running this to see it work:
create table t(i int primary key);
create table u
(
j int foreign key references t(i),
k int foreign key references t(i)
);
The problem you have is that you have some data in your Purchases table where the value in the column on which you are trying to create the foreign key does not exist in the countries table's ID column.
To find them run a query like this:
select p.*
from dbo.purchases p
where not exists
(
select *
from dbo.countries
where ID = p.FK_DestinationCountryCode
)
Note that I think your column names are a little weird here, You shouldn't call a column FK_DestinationCountryCode just because it has a foreign key on it, and a "code" is not the same kind of thing as an "ID". Your purchases table's columns should probably be called DestinationCountryID and OriginCountryID.

How to alter type of a column who is references as Foreign key in other table?

I want to change the dataType of primary key from varchar to bigint.
I tried following command.
ALTER TABLE dbo.Company
ALTER COLUMN Id bigint
but it is not working as this column is referenced as the foreign key in other tables.
How can i change its type without loosing data of the table through Sql Query?
There are several steps to accomplish this. But the main thing, is that first you'll have to drop the key.
First drop the primary (change name_of_primary_key, with yours real):
ALTER TABLE dbo.Company DROP CONSTRAINT name_of_primary_key;
Change the data type (replace length with your desired):
alter table table alter column foreign_key_column bigint(length)
Then drop the foreign key from other tables (make this for every table, and replace the two arguments, with your real from the db):
ALTER TABLE table DROP FOREIGN KEY foreign_key_column;
Now, you change the data type of the foreign key column(replace length with your desired):
alter table table alter column foreign_key_column bigint(length);

T-SQL inserting data into table with foreign key

I'm using SQL Server 2014 to create and insert data into tables and came along a problem when it comes to populating a table with a foreign key constraint in it. I have a table user and and a table city which were created beforehand.
I used code to alter the user table to include a cityId foreign key from table city with this code:
ALTER TABLE [Schema].[user]
ADD cityId UNIQUEIDENTIFIER NOT NULL
CONSTRAINT usr_cid_fk
FOREIGN KEY (cityId) REFERENCES [Schema].[city] (cityId);
GO
Basically I modified the user table by adding a field called cityId which i made foreign key. now the problem is that when inserting data, in the first line
INSERT INTO [Schema].[user](name, surname, dob, gender, .. )
cityId cannot be found to be mapped. Dunno why it ain't showing. In the design view it is listed as a foreign key so there should be no problems.
Thanks a lot
try :
ALTER TABLE [Schema].[user]
ADD cityId NUMBER NOT NULL
CONSTRAINT usr_cid_fk
FOREIGN KEY (cityId) REFERENCES [Schema].[city] (cityId);
Note :
For ADD cityId UNIQUEIDENTIFIER NOT NULL
By the SQL standard, a foreign key must reference either the primary key or a unique key of the parent table. If the primary key has multiple columns, the foreign key must have the same number and order of columns. Therefore the foreign key references a unique row in the parent table; there can be no duplicates.

Altering multiple objects in in query

The code below is attempting to alter 2 columns at once in a table. Can it be done and am I just doing it wrong?
Alter table verdata
Add Primary Key(Asset_ID)
Add foreign key(Asdes) References AssetDesc(AssetDescription)
To add constraints in alter query,
follow the below,
ALTER TABLE ADD CONSTRAINT adds a table-level constraint to an existing table. Any supported table-level constraint type can be added via ALTER TABLE. The following limitations exist on adding a constraint to an existing table:
When adding a foreign key or check constraint to an existing table, Derby checks the table to make sure existing rows satisfy the constraint. If any row is invalid, Derby throws a statement exception and the constraint is not added.
All columns included in a primary key must contain non null data and be unique.
ALTER TABLE ADD UNIQUE or PRIMARY KEY provide a shorthand method of defining a primary key composed of a single column. If PRIMARY KEY is specified in the definition of column C, the effect is the same as if the PRIMARY KEY(C) clause were specified as a separate clause. The column cannot contain null values, so the NOT NULL attribute must also be specified.
For information on the syntax of constraints, see CONSTRAINT clause. Use the syntax for table-level constraint when adding a constraint with the ADD TABLE ADD CONSTRAINT syntax.
REFERENCE

Transfer data with different type Primary key

I'm redesigning very old DB where new tables have PK type UNIQUEIDENTIFIER and old tables have INT. There are also many relationships between tables. Can anyone help with how not to lose any relationships and change PK type when transferring data?
Old Table: Item(PK - itemID(int), FK - Vendor_Id(int), and Manufacture_Id(int) Manufacture ID is not as set FK but it should be in new table.
Let's say you have empty School and Student tables with UNIQUEIDENTIFIER typed primary keys named id.
Let's say the relationship between students and schools is many-to-one, via a school_id foreign key.
The old tables are called oldSchool and oldStudent and have id columns of type int. oldStudent
also has a foreign key named school_id.
Steps to take:
Extend all new tables that are referenced to by foreign keys with an extra column called old_id of type int. In the example table School would get this extra column:
ALTER TABLE School ADD old_id int;
All foreign key columns should get a sybling column of type int, called old_original_name. In our example
Student should get an extra old_school_id column
Temporarily disable foreign key constraints:
SET foreign_key_checks = 0;
Or, if that fails, drop all the foreign keys, to recreate them later, for example:
ALTER TABLE Student DROP FOREIGN KEY fk_school_id;
Also make those foreign key columns nullable:
ALTER TABLE Student MODIFY school_id int NULL;
Insert records from the old tables into the new tables, making sure the values of
primary keys and foreign keys are stored in the target's corresponding old_xxxxxx columns.
In the example, it would look like this:
INSERT INTO School (old_id, name, address)
SELECT id, name, address
FROM oldSchool;
INSERT INTO Student (name, class, old_school_id)
SELECT name, class, school_id
FROM oldStudent;
Update the foreign key columns which are null by looking up the new id via the old_xxxx foreign key values. In our example:
UPDATE Student
SET school_id = (
SELECT id
FROM School
WHERE old_id = Student.old_id);
Now make those foreign key columns not nullable again:
ALTER TABLE Student MODIFY school_id int NOT NULL;
Enable the foreign key constraints again.
SET foreign_key_checks = 1;
Or if you had to drop them, recreate them, for example:
ALTER TABLE Student
ADD CONSTRAINT fk_school_id
FOREIGN KEY (school_id)
REFERENCES School(id);
Optionally drop all the old_xxxxx columns from all your tables. In the example:
ALTER TABLE Student DROP COLUMN old_school_id;
ALTER TABLE School DROP COLUMN old_id;
Optionally drop all old tables. In the example:
DROP TABLE oldStudent;
DROP TABLE oldSchool;
Done.

Resources