February 12, 2004 at 7:18 am
Ok, I have the proverbial "Users" table. I am using a UniqueIdentifier as the Primary Key, however, I need to also have the "UserName" Field be Unique as well.
The problem is that I need only UserNames that are not NULL to be Unique. If the Field Value Is Null, I do not care. When I try to put a Constraint on that Field, the Constraint does NOT Ignore NULLS. Is this possible? Am I just not seeing something?
If it's not possible with a Constraint, then how can I create a Trigger that runs on UPDATE and INSERT and validates the UserName before Saving the Record??
February 12, 2004 at 9:11 am
Thanks! That did the trick!
February 13, 2004 at 2:47 pm
tymberwyld;
1) Reconsider your table design -- why would you allow NULL UserNames? What does that mean?
2) Here's another (IMO, more elegant) method that doesn't rely on procedural (trigger) logic. Creat a VIEW on the table with a unique index:
CREATE TABLE dbo.NoDupesExceptNull(
UniqueID int NOT NULL PRIMARY KEY CLUSTERED,
UserName varchar(35) NULL,
)
GO
CREATE VIEW dbo.vConstrainNoDupesExceptNull
WITH SCHEMABINDING
AS
SELECT UserName
FROM dbo.NoDupesExceptNull
WHERE UserName IS NOT NULL
GO
CREATE UNIQUE CLUSTERED INDEX udx_vConstrainNoDupesExceptNull
ON dbo.vConstrainNoDupesExceptNull(UserName)
GO
INSERT INTO dbo.NoDupesExceptNull
SELECT 1, 'TroyK' UNION ALL
SELECT 2, NULL UNION ALL
SELECT 3, NULL
GO
INSERT INTO dbo.NoDupesExceptNull
SELECT 4, 'TroyK'
GO
SELECT * FROM dbo.NoDupesExceptNull
GO
DROP VIEW dbo.vConstrainNoDupesExceptNull
DROP TABLE dbo.NoDupesExceptNull
HTH,
TroyK
February 16, 2004 at 6:32 am
Hmm, well, I lied, it's not really a "Users" table. It's more of an "Individuals" Table which stores Users and Contacts of Companies in the same table. The reason is complicated, but even a "Contact" record could eventually have a User name when they have "Signed-up" for access into our in-house application. I did not want a seperate Table for "Users" vs. "Contacts" because it was a lot of redundant data!
Thank you for your suggestion, but I try to get around using Temporary Tables. If there is something I can't do with the data I have (without creating a Temp Table) then I am designing the DB incorrectly (In my humble opinion ). Can you imagine creating a Temp table everytime a Record changes in that table? That's a lot of unneccessary processing.
Anyway, it works great with the Trigger, and I have even returned an Error Message stating why it failed...which will return the error to the VB.NET App as well.
CREATE TRIGGER dbo.trg_OnUpdateIndividual ON [Individuals]
FOR INSERT, UPDATE
AS
BEGIN
If (Select Max(Cnt) From (Select Count(inserted.UserName) As Cnt
From Inserted
Inner Join dbo.Individuals ON Inserted.UserName = dbo.Individuals.UserName
Group By Inserted.UserName) x) > 1
BEGIN
RaisError('The UserName must be Unique!', 16, 1)
ROLLBACK TRAN
END
END
February 16, 2004 at 10:42 am
The VIEW is intended to be permanent... not something you create/delete each time you enforce the constraint.
My script is ambiguous in this respect because I left the cleanup code (DROP VIEW... and DROP TABLE...).
In my example, the table "NoDupesExceptNull" is analagous to your "Individuals" table, and the VIEW is a permanent reference to that table.
Using a TRIGGER to enforce db integrity should be a last resort, and as shown in my example, is not necessary in this case. The error message from attempting a duplicate insert can be quite informative if you use a meaningful name for the index on the VIEW.
TroyK
February 16, 2004 at 10:46 am
P.S.
Some of your statements about your table indicates that it is not properly designed (i.e., normalized). I'd be happy to work through that with you if you can post more detail on the business rules and your current table design.
TroyK
Viewing 7 posts - 1 through 6 (of 6 total)
You must be logged in to reply to this topic. Login to reply