How to add surrogate key to related tables? - sql

I need to add a auto-inc surrogate key to three tables in my data warehouse:
Note: These are not the real table names
JakMaster (JakMasterId, Date) (PK) Note: JakMasterId is varchar(60)
JakToRoad (JakMasterId, Date) (FK)
JakToBig (JakMasterId, Date) (FK)
What steps should I take to add a surrogate key to these three tables so that the new keys reference each other correctly?
Thanks!

I'm assuming you are wanting to replace JakMasterId with an auto-increment field so the other two tables don't need a varchar(60) field and to improve query times, but that you are keeping JakMasterId as information.
-- set database single-user
-- drop foreign keys
create table NewMaster (ID int identity(1, 1), JakMasterId, Date))
insert NewMaster(JakMasterId, Date) select JakMasterId, Date from JakMaster
drop table JakMaster
sp_rename 'NewMaster', 'JakMaster'
alter table JakToRoad add MasterId int
alter table JakToBig add MasterId int
update JakToRoad set MasterId = JakMaster.ID
from JakToRoad
inner join JakMaster on JakMaster.JakMasterId = JakToRoad.JakMasterId
update JakToBig set MasterId = JakMaster.ID
from JakToBig
inner join JakMaster on JakMaster.JakMasterId = JakToBig .JakMasterId
alter table JakToRoad drop column JakMasterId
alter table JakToBig drop column JakMasterId
alter table JakToRoad add constraint FK_JTRtoJM foreign key (MasterId) references JakMaster (ID)
alter table JakToBig add constraint FK_JTBtoJM foreign key (MasterId) references JakMaster (ID)
-- reset database to multi-user

You might be able to do this in three steps within the DB to create the surrogate PK
Alter the table to create the surrogate key column. Except, it has to be nullable.
Write a small program to set the key values. It's a loop doing UPDATEs.
Alter the table to make the surrogate key column non-null, auto-increment, indexed, unique, etc.
Now you need to create the FK's.
Alter the table to add the FK column. Again, it must be nullable.
Write a small program to set the FK column. This is a SELECT (to get the PK row based on non-surrogate keys), and an UPDATE to the referencing table.
If necessary, alter the table to make the FK non-null. This isn't always necessary, it depends on the definition of the FK table's relationship with the PK table.
Repeat the FK creation for all other tables.

Related

Join two tables together with the use of a third table that contains composite keys from both?

I'm trying to combine two tables together with a third that is comprised of a single column that is a combination of the two tables primary key column. I've considered using substring to separate the column into parts that can be compared to either table's key column but I might be making it more difficult.
The problem here is your design; you need to fix it. You are storing a delimited value in your column, combinedcode, in your junction table.
What you should be doing is storing the 2 values in separate columns, and then creating your foreign keys on those values. This would look something like this:
CREATE TABLE dbo.Table1 (SomeID varchar(10) NOT NULL,
SomeValue varchar(20));
ALTER TABLE dbo.Table1 ADD CONSTRAINT PK_Table1 PRIMARY KEY (SomeID);
GO
CREATE TABLE dbo.Table2 (OtherID varchar(10) NOT NULL,
OtherValue varchar(20));
ALTER TABLE dbo.Table2 ADD CONSTRAINT PK_Table2 PRIMARY KEY (OtherID);
GO
CREATE TABLE dbo.JunctionTable (SomeID varchar(10) NOT NULL,
OtherID varchar(10) NOT NULL);
ALTER TABLE dbo.JunctionTable ADD CONSTRAINT FK_JunctionTable1 FOREIGN KEY (SomeID) REFERENCES dbo.Table1(SomeID);
ALTER TABLE dbo.JunctionTable ADD CONSTRAINT FK_JunctionTable2 FOREIGN KEY (OtherID) REFERENCES dbo.Table2(OtherID);
Depending on your design, you may want to make it so that the value in the junction table are are unique:
ALTER TABLE dbo.JunctionTable ADD CONSTRAINT PK_JunctionTable PRIMARY KEY (SomeID,OtherID);
Then, to do your JOINs it would be as simple as:
SELECT {Your Columns}
FROM dbo.Table1 T1
JOIN dbo.JunctionTable JT ON T1.SomeID = JT.SomeID
JOIN dbo.Table2 T2 ON JT.OtherID = T2.OtherID;
You mase use join with LIKE operator.
Something like this for the first table:
combinedcode LIKE '%' + purchasecode
And that for the second
combinedcode LIKE receiptcode + '%'
Although this code may not be good in performance. If you can you should change your data model

Drop one to one relationship tables

I created two tables which are 1 to 1.
So one table has foreign key from another.
How can I drop the tables? I did not use on delete cascade while creating tables.
So I either have to somehow change it, or IDK..
I have done this.
CREATE TABLE hotel(
id_hotel
...
)
CREATE TABLE Manager(
ID_Manager
...
id_hotel FOREIGN KEY ...
)
and then I added
ALTER TABLE Hotel ADD id_manager INT NOT NULL;
ALTER TABLE Hotel ADD FOREIGN KEY (id_manager) REFERENCES Manager(id_manager);
You first have to drop the table with the foreign key in the column, eg: If you have 2 entities one named driving_license and the other person, and you store the id from person in the table driving_license, you have to first drop the table driving_license
Or if you are using MySQL: You can write:
SET_FOREIGN_KEY_CHECKS=0;
//Drop however you want
SET_FOREIGN_KEY_CHECKS=1
For MSSQL you can use:
ALTER TABLE <yourtablename> NOCHECK CONSTRAINT ALL
And then drop your table

how to validate values of a column with column of another table which is not a primary key

I have a table DRIVER with a column having following specification
BranchPostedAt int not null
In another table viz. CompanyBranch, I have following column
BranchId int not null
In the second table viz. CompanyBranch, primary key is set on two columns as under
CompanyId int not null
BranchId int not null
Is there any way by which I can set a foreign reference key on dbo.Driver.BranchPostedId referencing dbo.CompanyBranch.BranchId at the time of creating dbo.Driver?
Any help?
An alternative would be to create a trigger, but this is a little messy. I prefer previous posters answer to create a new identiy primary key on CompanyBranch [CompanyBranchId] and reference that as a foreign key.
Something like:
CREATE TRIGGER trDriver
ON DRIVER
AFTER INSERT, UPDATE
AS
BEGIN
SET NOCOUNT ON;
IF NOT EXISTS(Select *
from CompanyBranch cb
Inner join inserted i on i.BranchPostedAt = cb.BranchId )
BEGIN
RAISERROR ('The BranchPostedAt is not in the CompanyBranch table.', 16, 1);
ROLLBACK TRANSACTION;
RETURN
END
END
GO
No, it is not possible. To create a foreign key, the key that you "reference" to in the other table must be a UNIQUE or PRIMARY KEY constraint.
You can consider few options:
Make BranchId in CompanyBranch table as Unique
Create a new PRIMARY KEY in CompanyBranch - CompanyBranchId, and
reference it in your Driver table
Based on your Question and Comments, This is what you have
TABLE dbo.CityMaster
CityId INT NOT NULL PRIMARY KEY,
TABLE dbo.CompanyBranch
CompanyID INT NOT NULL,
BranchID INT NOT NULL REFERENCES dbo.CityMaster(CityId),
CONSTRAINT PK... PRIMARY KEY (CompanyID,BranchID)
TABLE dbo.DRIVER
BranchPostedAt INT NOT NULL,
Now, Since BranchID references CityMaster.City column and BranchID is not a unique column in dbo.CompanyBranch, You cannot use BranchID as a Foreign key reference for your DRIVER.BranchPostedAt.
Option 1
You should use dbo.CityMaster which contain the master list of values which will be stored in DRIVER.BranchPostedAt.
Option 2
If you want to dbo.CompanyBranch, you would then have to create a new unique column(you can even use an identity column to make it transparent) may be CompanyBranchID (apart from your existing composite key) and use it as a foreign key reference. Your existing composite key cannot be used as is.
having CompanyBranch Table only is meaningfull when you have more than one Company and also there is possibility that companies share branches with each other, otherwise you don't need such table. you just then have Company and Branch Tables and in Branch Table, BranchID is unique and you have a foreign key CompanyID in Branch Table Too.

How to ensure that a foreign key value is not repeated

I am stupid about SQL so here's a trivial question.
If I have a table structure like so.
User:
Id (primary key)
UserProfile:
UserId (foreign key, primary key in user table)
OtherStuff
I have set the UserProfile.UserId as the foreign key linking it to the User.Id column.
How do I ensure that people don't enter more than one row for the same user in the UserProfile table?
Do I set a UNIQUE constraint on the UserProfile.UserId column? That's the only way I can think of.
Create a unique constraint. Also, assuming since it's an ID column you don't want to allow null values you can also modify the column to not accept nulls. You'll have to define alter the table with a NOT NULL condition on the column if you don't want to allow null values.
You can use this syntax to alter your userprofile table and add a unique constraint:
ALTER TABLE userprofile
ADD CONSTRAINT <constraint_name> UNIQUE (userid);
If you don't want to allow null values:
ALTER TABLE [Table]
Alter COLUMN [Column] [Data Type] not null;

SSIS Lookup multiple dates in my fact table, how to pull this off using one date dimension?

In my SSIS/DW project, I have a DIM.DATE dimension which is linked to my FACT table by a surrogate key as follows:
ALTER TABLE FACT.SALES ADD date_id INT NOT NULL
ALTER TABLE FACT.SALES WITH CHECK ADD CONSTRAINT FK_dim_date FOREIGN KEY (date_id) REFERENCES DIM.DATE(date_id)
This creates a "date_id" in my fact table, now during my SSIS import process I have a date column being passed (shipped_date), I use this to look up the DIM.DATE table and pass in the surrogate key in my dimension.
This works great, but now I need to have a few different date dimensions for invoice date, received date, etc.
I am confused as to how to make use of the existing DIM.DATE to do this?
I could then add more columns into my fact table..
-- add column into fact table
ALTER TABLE FACT.SALES ADD shipped_date_id INT NOT NULL
ALTER TABLE FACT.SALES ADD invoice_date_id INT NOT NULL
-- add foreign key
ALTER TABLE FACT.SALES WITH CHECK ADD CONSTRAINT FK_shipped_date FOREIGN KEY (shipped_date_id) REFERENCES DIM.DATE(date_id)
ALTER TABLE FACT.SALES WITH CHECK ADD CONSTRAINT FK_invoice_date FOREIGN KEY (invoice_date_id) REFERENCES DIM.DATE(date_id)
But when I do my lookup, I can only pass in the "date_id" column.. I am confused how to make this work all together.
Anyone able to clear this up for me?
You have to use multiple LookUp transforms... 1 for each DateKey field in the fact table.