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
 General SQL Server Forums
 Database Design and Application Architecture
 Enforce constraint based on more than one record

Author  Topic 

charlemagne
Starting Member

3 Posts

Posted - 2010-03-30 : 22:56:21
I have a table with a definition like this:

ID int autonumber PK
Name nchar(30)
Deleted bit
... some other fields ...


I would like to have no more than one active record (Deleted = 0) with a given name, but any number of inactive records with any given name. If someone deletes a record (marks it inactive, not actually using SQL DELETE), and then someone else creates a new record with the same name, there should be no problem. There should only be a constraint violation if there is already another record with Deleted = 0 and the same name.


I can see two ways of doing this:

1) have two name fields: main [unique] and backup [not unique], nulling the main field when the record is marked inactive, and copying back from the backup if the record is marked active again


2) have two tables, moving deleted records into the historical entries table


Both of these feel hackish -- does anyone know of a better way?

tkizer
Almighty SQL Goddess

38200 Posts

Posted - 2010-03-30 : 23:13:08
I prefer option 2 over option 1, but I would instead enforce it through a trigger or simply in a stored procedure with locks.

Tara Kizer
Microsoft MVP for Windows Server System - SQL Server
http://weblogs.sqlteam.com/tarad/

Subscribe to my blog
Go to Top of Page

LoztInSpace
Aged Yak Warrior

940 Posts

Posted - 2010-03-31 : 07:14:24
How about an "Active" table that has a FK to the original table's PK and a unique constraint on the name? You would then assume everything in the main table was deleted unless it had a corresponding entry in the active table. No triggers, no locks & proper RI.
You can create a view to the main table joined to the active table to make life easier in day to day use.
Go to Top of Page

DBA in the making
Aged Yak Warrior

638 Posts

Posted - 2010-03-31 : 07:28:49
How about replacing the Deleted column with a VersionNo (INT) column. VersionNo = 0 means it's the current record. Anything else means the record has been deleted.

When you add a record with Name = 'John', the VersionNo will be 0. To delete the 'John' Record, simply find the maximum VersionNo for all 'John' Records, add one to it, then update the current 'John' record with that value.

This offers 2 advantages:

1 - You can have a unique index on the Name, VersionNo columns

2 - You'll be able to see the order in which the records were deleted.

Another way to do it would be to have a DeletedDate column. If it's NULL, then it's the current record. To delete a record, update it with the GETDATE(). This offers the same advantages as the first, but also allows you to see exactly when each record was deleted. However, it will use an extra 4 bytes per row over the first method.

There are 10 types of people in the world, those that understand binary, and those that don't.
Go to Top of Page

LoztInSpace
Aged Yak Warrior

940 Posts

Posted - 2010-03-31 : 07:51:19

a) It's the same problem setting versionNo to 0 as having a deleted flag
b) max will allow duplicates when 2 users update at the same time
Go to Top of Page

DBA in the making
Aged Yak Warrior

638 Posts

Posted - 2010-03-31 : 08:02:49
quote:
Originally posted by LoztInSpace


a) It's the same problem setting versionNo to 0 as having a deleted flag


If the problem is that there's not way to specify a constraint to stop 2 records both being active, because there will be multiple inactive (Deleted = 1) records, then a VersionNo solves that problem, because it allows a unique constraint/index to be places on the 2 columns in question. Each deleted record has it's own VersionNo.
quote:

b) max will allow duplicates when 2 users update at the same time


That's what locks are for.

There are 10 types of people in the world, those that understand binary, and those that don't.
Go to Top of Page

byrdzeye
Starting Member

14 Posts

Posted - 2010-04-09 : 14:06:20
feels hackish...
To implement a unique constraint you have to implement a number of tables, processes. I don't think the constraint belongs here.
Just implement the 'business rule' in a trigger that returns a violation error if needed. Nothing else needed.
Go to Top of Page

DBA in the making
Aged Yak Warrior

638 Posts

Posted - 2010-04-09 : 14:37:17
quote:
Originally posted by byrdzeye

feels hackish...
To implement a unique constraint you have to implement a number of tables, processes. I don't think the constraint belongs here.
Just implement the 'business rule' in a trigger that returns a violation error if needed. Nothing else needed.



Hackish? I'd call using a trigger to implement a unique constraint "Hackish".

I'm not sure what you mean by "you have to implement a number of tables, processes".

Nothing else needed? How about an index to make the trigger run more efficiently? While you're at it, why not make it a unique trigger, and then hey, guess what, the trigger in now redundant.

------------------------------------------------------------------------------------
Any and all code contained within this post comes with a 100% money back guarantee.
Go to Top of Page
   

- Advertisement -