Please start any new threads on our new site at https://forums.sqlteam.com. We've got lots of great SQL Server experts to answer whatever question you can come up with.

 All Forums
 SQL Server 2005 Forums
 Transact-SQL (2005)
 Unique Constraint on 2 tables

Author  Topic 

Cowski
Starting Member

30 Posts

Posted - 2009-12-10 : 15:34:04
My project is this. We have 2 table "HR" and "AgentLogin". Both have a field called "username". What we want to do is prevent any duplicate usernames from being inserted into either table. We would like an error thrown.
We're thinking of using a constraint. I can get it to work on a single table but having issues with checking both tables before the insert statement activates.

Suggestions?

Thanks!!

DP978
Constraint Violating Yak Guru

269 Posts

Posted - 2009-12-10 : 16:10:38
can you set 2 variables to True/False and then do a check, if both are TRUE then continue the insert.

Declare @Table1OK int
Declare @Table2OK int

Set @Table1OK = 0
Set @Table2OK = 0

...Use your code to see if the record exists on table 'HR'...if it doesnt and your code returns a null record set...then...

Set @Table1OK = 1

...Use your code to see if the record exists on table 'AgentLogin'...if it doesnt and your code returns a null record set...then...

Set @Table2OK = 1

If @Table1OK = 1 and @Table2OK = 1
Then
...
Insert the User into whichever table
...
ELSE

Print 'Failed due to duplicate'

EDIT: Or UNION the distinct UserName's from your 2 tables and if it exists in there then throwback an error, if it doesn't then proceed.
Go to Top of Page

Cowski
Starting Member

30 Posts

Posted - 2009-12-10 : 16:20:29
This sounds very doable, DP. Will run with something like this & see what happens. I'm thinking something along the lines of a stored proc with the username as a parameter.

Will keep you posted. Thanks!
Go to Top of Page

russell
Pyro-ma-ni-yak

5072 Posts

Posted - 2009-12-10 : 16:38:16
I'd probably do this with a trigger on each table.

Create Trigger AgentLogin_Usename on agentlogin
for insert, update
as
IF Exists(
select hr.username
from hr
join inserted i
on i.username = hr.username
)
BEGIN
RaisError('username exists in hr table', 16, 1)
rollback
END
Go to Top of Page

DP978
Constraint Violating Yak Guru

269 Posts

Posted - 2009-12-11 : 08:28:42
He needs to check both tables to see if the User ID is there, will that check both? Or will it only check the first and then insert if ok, and then the second and insert if ok. Would there be a chance that it catches the duplicate on the second table and at that point has already inserted the ID into table 1?
Go to Top of Page

Cowski
Starting Member

30 Posts

Posted - 2009-12-11 : 08:53:37
quote:
Originally posted by russell

I'd probably do this with a trigger on each table.



We considered a trigger but doesn't a trigger react to an event that has already taken place? We need this to happen before anything happens.
I've got a stored procedure in the making that will be called that can check for the username & react accordingly.
Go to Top of Page

DP978
Constraint Violating Yak Guru

269 Posts

Posted - 2009-12-11 : 09:57:37
The rollback will undo whatever activated the trigger. So I do not believe that part is a problem.
Go to Top of Page

russell
Pyro-ma-ni-yak

5072 Posts

Posted - 2009-12-11 : 10:11:44
Put a unique constraint on the username field of each table. Put a trigger on each table that checks the other. No dupes this way. And as DP978 said, the trigger will prevent the insert if the username exists in the other table.
Go to Top of Page

russell
Pyro-ma-ni-yak

5072 Posts

Posted - 2009-12-11 : 10:14:36
[code]
create table hr (username varchar(32) unique);
GO
create table AgentLogin (username varchar(32) unique);
GO
Create Trigger AgentLogin_Usename on agentlogin
for insert, update
as
IF Exists(
select hr.username
from hr
join inserted i
on i.username = hr.username
)
BEGIN
RaisError('username exists in hr table', 16, 1)
rollback
END
GO
Create Trigger Hr_Usename on hr
for insert, update
as
IF Exists(
select a.username
from agentlogin a
join inserted i
on i.username = a.username
)
BEGIN
RaisError('username exists in agentlogin table', 16, 1)
rollback
END
GO

insert AgentLogin values('cowski'); -- succeeds
insert hr values('cowski') -- fails

select * from AgentLogin;
select * from hr

drop table hr
drop table AgentLogin[/code]
Go to Top of Page

RyanRandall
Master Smack Fu Yak Hacker

1074 Posts

Posted - 2009-12-11 : 10:47:42
Here's another option (using a function and a check constraint on each table)...

drop table t1
drop table t2
drop function dbo.username_count
go

create table dbo.t1 (username varchar(9))
create table dbo.t2 (username varchar(9))
go

create function dbo.username_count(@username varchar(9)) returns tinyint as
begin
return (select count(*) from (select * from t1 union all select * from t2) a where username = @username)
end
go

alter table dbo.t1 with nocheck add constraint t1_unique_username check (dbo.username_count(username) <= 1)
alter table dbo.t2 with nocheck add constraint t2_unique_username check (dbo.username_count(username) <= 1)

select dbo.username_count('a') as Count

insert t1 select 'a'
insert t2 select 'b'
insert t2 select 'a'
insert t1 select 'c'
insert t1 select 'b'

select dbo.username_count('a') as Count
select dbo.username_count('d') as Count

select * from t1
select * from t2


Ryan Randall - Yak of all trades
Solutions are easy. Understanding the problem, now, that's the hard part.
Go to Top of Page

Cowski
Starting Member

30 Posts

Posted - 2009-12-11 : 11:10:27
Here's what I worked up for a stored procedure. This seems to be working so far:

USE [master]
GO
/****** Object: StoredProcedure [dbo].[ausp_UserNameCheck] Script Date: 12/11/2009 11:07:17 ******/
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO

ALTER PROCEDURE [dbo].[ausp_UserNameCheck]
-- Add the parameters for the stored procedure here
@varUserName varchar(20)

AS
BEGIN
-- SET NOCOUNT ON added to prevent extra result sets from
-- interfering with SELECT statements.
SET NOCOUNT ON;

Declare @varUser varchar(20)
Declare @varCountHR int
Declare @varcountAgentLogin int

Select @varCountHR = count(*) from [AdventureWorks].[dbo].[JohnsHR] where [AdventureWorks].[dbo].[JohnsHR].[UserName] = @varUserName
Select @varCountAgentLogin = count(*) from [AdventureWorks].[dbo].[JohnsAgentLogin] where [AdventureWorks].[dbo].[JohnsAgentLogin].[UserId] = @varUserName

if @varCountHR >= 1
--Print 'ERROR!! Duplicate username exists within the HR table.'
RaisError('Error. Duplicate Username exists with the HR table.', 16, 1)
Else
Print 'Username confirmed. Inserting into HR table...'

if @varCountAgentLogin >= 1
--Print 'Error! Duplicate username exists within the AgentLogin table.'
RaisError('Error. Duplicate Username exists with the AgentLogin table.', 16, 1)
Else
Print 'Username confirmed. Inserting into AgentLogin table...'
--Insert record into the AgentLogins table.


END

Go to Top of Page

russell
Pyro-ma-ni-yak

5072 Posts

Posted - 2009-12-11 : 11:16:55
If someone inserts without your SP your data is corrupt. Should either use triggers as I showed, or Check constraint as Ryan showed.
Go to Top of Page

Cowski
Starting Member

30 Posts

Posted - 2009-12-11 : 12:31:14
Russell,

Thanks for the code you wrote up. 95% of it makes sense & I'm going to tweak it now to run with my 2 big test tables. (well lunch first! ).
I do have a question though. The code:
select	a.username
from agentlogin a
join inserted i <--
on i.username = a.username


What does the inserted i function as?
Thanks again & will report back.

Go to Top of Page

russell
Pyro-ma-ni-yak

5072 Posts

Posted - 2009-12-11 : 12:39:35
inserted is a logical table available inside of triggers that contains the record about to be inserted, or the record as it would look after an update. in other words, the "after" state of the update/insert.

deleted is another logical table that contains the "before" state.

check out BOL for full details: http://msdn.microsoft.com/en-us/library/ms189799.aspx

Go to Top of Page
   

- Advertisement -