Greg,
It looks to me like this will work. I don't think you 't need to check against
null unless you have ANSI NULLS off, since a.Phone = b.Phone
will not be true if either side is NULL, and I think you can leave off the
check that a.CustID <> b.CustID, unless something is funny with the
identity column.
If you are using SQL Server 2000, however, you can enforce non-null
duplicates without a trigger (see below).
You can test to see which solution turns out to be more efficient -
either might be helped by an index to speed up the checking.
Here's how to do it (Both Ivan Arjentinski and I posted this several
months ago):
CREATE TABLE dbo.Customers
(
CustID int NOT NULL IDENTITY (1, 1),
Name varchar(50) NULL,
Address varchar(50) NULL,
City varchar(50) NULL,
State varchar(2) NULL,
Zipcode varchar(9) NULL,
Phone varchar(20) NULL,
NoDuplicates as CASE WHEN Phone IS NULL
THEN CONVERT(varchar(21),CustID) ELSE '*'+Phone END,
CONSTRAINT Customers_NoDupPhone UNIQUE (NoDuplicates)
) ON [PRIMARY]
GO
The computed column NoDuplicates is enforced to be unique, and
since it contains the phone number whenever the phone number is not
null, there can be no duplicate phone numbers. When the phone
number is null, it contains the primary key, which is unique.
There is the chance that a primary key and a phone number will match,
so in this case I store the phone number with a non-numeric character
on the left, so it can't match a CustID.
I'm virtually certain that you can't put a unique constraint on a computed
column in 7.0, since unique constraints are implemented with indexes,
and indexes on computed columns are new to SQL Server 2000.
Yet another solution is to create a view consisting of all the customers
with non-null phone numbers and enforce the uniqueness there.
Steve Kass
Drew University
> I've just tried writing my first trigger that would enforce non-null
> duplicates. This is my first attempt at it. It seems to work (I also
> noticed that Query Analyzer allowed the transaction if I didn't include
> the Rollback).
> Can anyone let me know this looks like an appropriate way to write this
> trigger, or if I can do things more efficiently? My (simplified) table,
> index, and trigger definitions are as follows:
> ==============
> CREATE TABLE dbo.Customers
> (
> CustID int NOT NULL IDENTITY (1, 1),
> Name varchar(50) NULL,
> Address varchar(50) NULL,
> City varchar(50) NULL,
> State varchar(2) NULL,
> Zipcode varchar(9) NULL,
> Phone varchar(20) NULL,
> ) ON [PRIMARY]
> GO
> ALTER TABLE dbo.Customers ADD CONSTRAINT
> PK_Customers PRIMARY KEY CLUSTERED
> (
> CustID
> ) ON [PRIMARY]
> GO
> CREATE NONCLUSTERED INDEX IX_Customers_Phone ON dbo.Customers
> (
> Phone
> ) ON [PRIMARY]
> GO
> CREATE TRIGGER tCustomerUniquePhone ON dbo.Customers
> FOR INSERT, UPDATE
> AS
> -- Only if Phone number was changed
> IF NOT UPDATE(Phone)
> RETURN
> -- Don't allow duplicates
> IF EXISTS (SELECT *
> FROM inserted a
> INNER JOIN Customers b ON a.Phone = b.Phone
> WHERE a.Phone IS NOT NULL AND a.Phone IS NOT NULL AND
> a.CustID<>b.CustID)
> BEGIN
> RAISERROR ('Duplicate Phone numbers are not allowed.', 16, 1)
> ROLLBACK TRANSACTION
> END
> GO
> ==============
> Thanks for the help,
> --
> Greg