SQL Server : create a foreign key with a condition - sql

I'm designing a new database for a company, trying to keep strict constraints with foreign keys etc for integrity. I have a table [Member] which holds companies on the system. This table has a column of [internalContact] for the user in our company who deals with this member which has a foreign linked to the users table by user id.
What I would like to know is if it is possible to assign a condition to the foreign key, since the users table contains internal and external users. ie. for the field to only accept a user id where the user type is 5. Can this be done, or can I only control this in my application code?
Thanks

You can use a check constraint for this.
(The code is untested some syntax errors will be in there)
CREATE TABLE Member
(
P_Id int NOT NULL,
LastName varchar(255) NOT NULL,
FirstName varchar(255),
Address varchar(255),
City varchar(255),
InternalContactId
CONSTRAINT chk_Person CHECK (isInternalUser(internalContactId) > 0)
)
ALTER TABLE Member
ADD FOREIGN KEY (InternalContacId)
REFERENCES Persons(P_Id)
Then just create a function isInternalUser that returns 1 if user in ok to be an internal contact
CREATE FUNCTION isInternalUser ( #userId int(10) )
RETURNS int
AS
BEGIN
DECLARE #tmp int
SELECT #tmp = count(*)
FROM users
WHERE userId = #UserId and <check to see if user is internal>
RETURN(#CtrPrice)
END
GO

Related

Stored procedure with multiple tables with foreign key

I am working on an event management project. In that project, I have a form in admin panel as add event which contains events name, category, sub-category, event admin etc and more. And in the database, I have different tables like event category, event sub-category.
And also I have a table that is cultural event which includes form fields and foreign key. I pass event catid, event sub-cat id.
On button click that cultural event is added.
I want to insert data in their tables and I want id that I gave in cultural event table.
On single click I want to insert this
How can I achieve this? Using a stored procedure?
CREATE TABLE EVENT_SCAT (ESUBCAT_ID INT NOT NULL PRIMARY KEY, ECAT_ID INT NOT NULL FOREIGN KEY REFERENCES EVENT_CAT(ECAT_ID), ESUBCAT_NAME VARCHAR(255) NOT NULL, )
create table EVENT_CAT (ECAT_ID INT NOT NULL IDENTITY PRIMARY KEY, ECAT_NAME VARCHAR(255)NOT NULL, EID INT NOT NULL FOREIGN KEY REFERENCES EVENTDETAILS(EID)
CREATE TABLE Cultural_E (c_ID INT NOT NULL IDENTITY PRIMARY KEY, cEVENT_NAME VARCHAR(255) NOT NULL, cE_SDATE DATE NOT NULL, cE_EDATE DATE NOT NULL, SE_RULES1 VARCHAR(MAX), SE_RULES2 VARCHAR(MAX), SE_RULES3 VARCHAR(MAX), cE_RULES4 VARCHAR(MAX), cE_EFEES INT, EID INT NOT NULL FOREIGN KEY REFERENCES EVENTDETAILS(EID), ECAT_ID INT NOT NULL FOREIGN KEY REFERENCES EVENT_CAT(ECAT_ID) )
and i have form in asp.net which includes all fields in single form but there are different tables with foreign keys. and i want id of ecat id and subcatid in last table i.e Cultural_e.
for ex:THESE ARE TABLE
eVENT_T
ID ENAME EADMIN
1 CULTURAL NIKHIL
E_CAT
ID ECAT_NAME E_iD
1 SINGING 1
event_scat
ID eCAT_iD ESUBCAT_NAME
1 1 SOLO
NOW I HAVE TABLE THAT IS CULTURAL_T
THESE TABLE HAVE ITS OWN FILEDS AS WELL AS FOREIGN KEY LIKE EID ,ECAT_ID AS YOU CAN SEE ABOVE
AND I HAVE FORM IN ASP.NET AND FORM CONTAINS TEXTBOX TO ENTER DATA OF ALL THESE TABLE.
SO PLZ TELL ME HOW TO ACHIEVE THIS
THANK YOU
As per my understanding of your question,try to use triggers rather than stored procedures if possible.
CREATE TRIGGER InsertEvents
AFTER INSERT ON EVENT_CAT
BEGIN
/* Insert Query to EVENT_SCAT */
/* Insert Query to cultural */
END

SQL Server 2008 stored procedure for a table having two foreign keys and both of them is a composite key

I have the following tables :
create table ApartmentInfo(
ApartmentId int primary key identity,
ApName nvarchar(50))
create table [User](
UserId int primary key identity,
FirstName nvarchar(50),
LastName nvarchar(50),
Username nvarchar(50),
[Password] nvarchar(50),
[Description] nvarchar(200))
create table ApUser(
ApartmentId int foreign key references ApartmentInfo(ApartmentId),
UserId int foreign key references [User](UserId),
primary key(ApartmentId,UserId))
Summary of the usage is: suppose I have 10 apartments in my Apartmentinfo table and 3 users in the [User] table.
Now I want to write a stored procedure such that:
every UserId has all 10 ApartmentId's, and whenever a new apartment is created in ApartmentInfo table it will also be added in ApUser table again having all 3 userId's.
And if a new user is created in User table then it will also have all the 10 ApartmentId's related with it in ApUser table.
Thanks in advance, I am new to SQL Server and I don't know how it can be done or not but, if it is possible then please let me know, I will be grateful to you, thanks.
If you're not dead set on using a stored procedure this use case seems like an excellent fit for server side triggers:
IF EXISTS (SELECT * FROM sys.triggers WHERE object_id = OBJECT_ID(N'[dbo].[trigger_insert_apartment]'))
DROP TRIGGER [dbo].[trigger_insert_apartment]
GO
CREATE TRIGGER trigger_insert_apartment
ON ApartmentInfo FOR INSERT
AS INSERT ApUser(ApartmentId, UserId ) SELECT i.ApartmentId, u.UserId FROM [User] AS u, inserted AS i
GO
IF EXISTS (SELECT * FROM sys.triggers WHERE object_id = OBJECT_ID(N'[dbo].[trigger_insert_user]'))
DROP TRIGGER [dbo].[trigger_insert_user]
GO
CREATE TRIGGER trigger_insert_user
ON [User] FOR INSERT
AS INSERT ApUser(ApartmentId,UserId ) SELECT a.ApartmentId, i.UserId FROM ApartmentInfo AS a, inserted AS i
GO
These two triggers will insert all apartments or users into the apinfo table when you add a new user or apartment, and if I understood your question that was what you wanted?
To address your question about what you'd do to associate apartments with users IF YOU WANTED TO LATER...
If you're restricting which apartments a user has access to view, I would NOT associate them individually to every user. BUT, if they're manually adding a "watch" on an apartment in your application, then this is ok to do. If you want to only show them a certain set of apartments, try to group them in a logical way if you can. So maybe have an ApartmentGroup lookup table:
ApartmentGroup(ApartmentGroupId (Int), ApartmentGroupName varchar(50))
and assign an ApartmentGroupId to each apartment. Then you can have a join table for ApUser and ApartmentGroup. That way you're not associating every apartment with every user.
However, if you want to add the apartment to each user still, then in your InsertApartment stored procedure, just insert it into the ApUser table as well.

SQL Server 2008 Foreign Keys that are auto indexed

Are Foreign Keys in SQL Server 2008 are automatically indexed with a value? For Example. if I add a value in my Primary key (or auto incremetend) in may parent table will the table that has a foreign key referenced to that key will automatically have the same value? or I Have to do it explicitly?
No, if you create a foreign key in a child table, it will not automatically get populated when a parent row gets inserted. If you think about this it makes sense. Let's say you have a table like:
CREATE TABLE dbo.Students
(
StudentID INT IDENTITY(1,1) PRIMARY KEY,
Name SYSNAME
);
CREATE TABLE dbo.StudentLoans
(
LoanID INT IDENTITY(1,1) PRIMARY KEY,
StudentID INT FOREIGN KEY REFERENCES dbo.Students(StudentID),
Amount BIGINT -- just being funny
);
What you are suggesting is that when you add a row to Students, the system should automatically add a row to StudentLoans - but what if that student doesn't have a loan? If the student does have a loan, what should the amount be? Should the system pick a random number?
Typically what will happen in this scenario is that you'll be adding a student and their loan at the same time. So if you know the loan amount and the student's name, you can say:
DECLARE
#Name SYSNAME = N'user962206',
#LoanAmount BIGINT = 50000,
#StudentID INT;
INSERT dbo.Students(Name)
SELECT #Name;
SELECT #StudentID = SCOPE_IDENTITY();
INSERT dbo.StudentLoans(StudentID, Amount)
SELECT #StudentID, #LoanAmount;

Foreign Key is null when insert using Stored Procedure

I've created a insert stored procedure with two tables like in the exapmle:
Table NameAge
CREATE TABLE [dbo].[Assignment3_NameAge]
(
userID int PRIMARY KEY IDENTITY(1,1),
Name varchar(255) NOT NULL,
Age int NOT NULL
)
Table Hobbies
CREATE TABLE [dbo].[Assignment3_Hobbies]
(
hobbiesID int Identity(1,1) Primary Key,
userID int Foreign Key references Assignment3_NameAge(userID),
hobbies varchar(255) NOT NULL,
)
Insert Stored Procedure
CREATE PROCEDURE [dbo].p_Assignment3Join_ins
#Name nvarchar(100),
#Age int,
#Hobbies nvarchar(100)
AS
INSERT INTO [TABLE].[dbo].[Assignment3_NameAge]
([Name]
,[Age])
VALUES (#Name,#Age)
INSERT INTO [TABLE].[dbo].[Assignment3_Hobbies]
([Hobbies])
VALUES (#Hobbies)
The problem is that when i run the stored procedure the table Hobbies has a null value for userid(the foreign key)
What am i doing wrong?
You should provide the key of the Assignment3_NameAge value you want to insert into Assignment3_Hobbies.
If you want the last inserted you can use SCOPE_IDENTITY() from SQL Server(if you're using SQL Server) or equivalent. It will give you the last inserted value from Assignment3_NameAge
I am guessing this is SQL Server based on the IDENTITY column. Correct?
The first insert creates a user, but there is no user ID being set on the insert of the hobby. You need to capture the identity value from the first insert to be used in the second insert. Have you gon over the system functions available?
You're not supplying a value for it, SQL won't automagically fill the value in for you even though you've created a Foreign Key relationship. It's your job to populate the tables.

How can I insert a set of child records while updating the parent?

I'm using SQL Server 2005 and wish to create a number address records, updating the contact records with the new Id's:
Take the following tables
create table contact(id int primary key identity, home_address_id int, work_address_id int)
create table address(id int primary key identity, street varchar(25), number int)
And foreign keys:
ALTER TABLE dbo.contact ADD CONSTRAINT FK_contact_address1 FOREIGN KEY (home_address_id) REFERENCES dbo.address(id)
ALTER TABLE dbo.contact ADD CONSTRAINT FK_contact_address2 FOREIGN KEY (work_address_id) REFERENCES dbo.address(id)
some dummy data
insert into contact default values
insert into contact default values
insert into contact default values
How can I insert a default empty address record for all contacts who have no home address, and update the home_address_id in one go?
The first part is simple:
insert into address(street) select null from contact where home_address_id is null
I can even get the newly create address id's:
declare #addressTable table(id int)
insert into address(street)
OUTPUT INSERTED.Id INTO #addressTable
select null from contact where home_address_id is null
Here's the new id's
select * from #addressTable
But how to update the contact table with these new Id's?
If possible, I would suggest normalizing your database by adding a Contact_Addresses table:
CREATE TABLE Contact_Addresses
(
contact_id INT NOT NULL,
address_id INT NOT NULL,
address_type VARCHAR(10) NOT NULL,
CONSTRAINT PK_Contact_Addresses PRIMARY KEY CLUSTERED (contact_id, address_id, address_type),
CONSTRAINT FK_ContactAddresses_Contacts (contact_id) REFERENCES Contacts (id),
CONSTRAINT FK_ContactAddresses_Addresses (address_id) REFERENCES Addresses (id),
CONSTRAINT CK_ContactAddresses_address_type CHECK address_type IN ('HOME', 'WORK')
)
Next, I would suggest not putting "dummy" records in your database. It's going to end up causing headaches down the road. The database should contain an accurate record of the data in your system. If you want to display some value by default when no address exists in the system for a contact then handle that in your UI.
If you really must though, then the following code should do the trick:
;WITH C_CTE AS
(
SELECT
id,
home_address_id,
ROW_NUMBER() OVER(ORDER BY id) AS seq
FROM
Contacts
),
(
SELECT
id,
ROW_NUMBER() OVER(ORDER BY id) AS seq
FROM
Addresses
)
UPDATE
C_CTE
SET
home_address_id = A.id
FROM
C_CTE C
INNER JOIN A_CTE A ON A.seq = C.seq
I would do it from the moment you get a new contact, thusly:
[receive contact information]
//prior to inserting contact
declare #homeAddress int, #workAddress int
[insert home address here (real or default based on input)]
set #homeAddress = ##Identity
[insert work address here (real or default)]
set #workAddress = ##Identity
[insert contact here referencing #homeAddress & #workAddress]
For the stuff already in your table, you're going to have to associate all of your null value ids to a contact id. Or, you could clear out your null value addresses, and modify the above statement to an update somehow (brain's not working at the moment, so all I'm coming up with is a cursor, and cursors are evil).