DBMS: MS Sql Server 2005, Standard
I would like to make a table constraint so that only one record has a specific value in a subset of the table (where the rows have a value in a specific column). Is it possible?
Example: I have entries in myTable that have a unique foreign key (fk1), and a column bit called isPrimary to indicate that this particular should be used by our application for special logic.
in an abstract expression is as follows:
myTable ------------- pk1 (int, not null) name (varchar(50), null) fk1 (int, not null) isPrimary (bit, not null)
I want to make sure that there is one and only one record with the isPrimary flag set to 1 for each unique value of fk1.
Sample data: This must be legal:
pk1 name fk1 isPrimary ---- ----- ----- ---------- 1 Bill 111 1 2 Tom 111 0 3 Dick 222 1 4 Harry 222 0
But this should not be (more than one, where fk = 111):
pk1 name fk1 isPrimary ---- ----- ----- ---------- 1 Bill 111 1 2 Tom 111 1 3 Dick 222 1 4 Harry 222 0
And not one of them (fk = 222 anywhere):
pk1 name fk1 isPrimary ---- ----- ----- ---------- 1 Bill 111 1 2 Tom 111 0 3 Dick 222 0 4 Harry 222 0
Is there a way to do this using a table constraint?
UPDATE So far, I have gone with Martin Smith's answer, although I will insist on the JohnFx refactor in the upcoming release, as this is the best long-term solution. However, I wanted to publish an updated UDF based on Raze2dust's answer in case future readers decide which is best suited to their needs.
CREATE FUNCTION [dbo].[OneIsPrimaryPerFK1](@fk1 INT, @dummyIsPrimary BIT) RETURNS INT AS BEGIN DECLARE @retval INT; DECLARE @primarySum INT; SET @retval = 0; DECLARE @TempTable TABLE ( fk1 INT, PrimarySum INT) INSERT INTO @TempTable SELECT fk1, SUM(CAST(isPrimary AS INT)) AS PrimarySum FROM FacAdmin WHERE fk1 = @fk1 GROUP BY fk1; SELECT @primarySum = PrimarySum FROM @TempTable; IF(@primarySum=1) BEGIN SET @retval = 1 END RETURN @retval END;
Changes:
- Used by @tempTable, not
tempTable (in v. memory written to disk) as udf required
- passed @ fk1 as a parameter, so I can choose uniqueness for one group of fk1 values.
- it was also difficult to pass isPrimary, although this is not necessary for logic, otherwise the SQL2005 optimizer will not run a check constraint when isPrimary is updated.