DBMS: MS Sql Server 2005, Standardvincolo unico all'interno di un gruppo di record in cui un certo valore è lo stesso
Mi piacerebbe fare un vincolo di tabella di avere un solo record ha un particolare valore all'interno di un sottoinsieme della tabella (dove le righe condividono un valore in una particolare colonna). È possibile?
Esempio: Ho record in myTable che hanno una chiave esterna non univoca (fk1), e una colonna di bit chiamato isPrimary a segnare che questo particolare dovrebbe essere utilizzato dal nostro app per logica speciale.
in astratto, sembra che questo:
myTable
-------------
pk1 (int, not null)
name (varchar(50), null)
fk1 (int, not null)
isPrimary (bit, not null)
voglio garantire che vi sia una e una sola record con la bandiera isPrimary impostato a 1, per ogni valore unico di FK1.
dati esempio: Questo dovrebbe essere legale:
pk1 name fk1 isPrimary
---- ----- ----- ----------
1 Bill 111 1
2 Tom 111 0
3 Dick 222 1
4 Harry 222 0
Ma questo dovrebbe non essere (più di una in cui fk = 111):
pk1 name fk1 isPrimary
---- ----- ----- ----------
1 Bill 111 1
2 Tom 111 1
3 Dick 222 1
4 Harry 222 0
E nemmeno questo dovrebbe (nessuno dove fk = 222):
pk1 name fk1 isPrimary
---- ----- ----- ----------
1 Bill 111 1
2 Tom 111 0
3 Dick 222 0
4 Harry 222 0
È c'è un modo per farlo con un vincolo di tabella?
UPDATE Sono andato con la risposta di Martin Smith, per ora, anche se sarò spingendo per il refactoring di JohnFx in una prossima release, in quanto è la migliore soluzione a lungo termine. Tuttavia volevo pubblicare la mia UDF aggiornata sulla base della risposta di Raze2dust, nel caso in cui i futuri lettori decidessero che è più adatto alle loro esigenze.
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;
Modifiche:
- Usato @tempTable piuttosto che
TempTable come richiesto dalla UDF
- passato @ fk1 come parametro in modo che posso (in memoria v scritti su disco.) selezionare per unicità all'interno di un gruppo di valori fk1.
- difficile doveva passare anche isPrimary anche se non è necessario per la logica della funzione , altrimenti l'ottimizzatore SQL2005 non verrà eseguito il vincolo di controllo quando isPrimary è aggiornato.
Sebbene la soluzione di JohnFx sia la migliore soluzione a lungo termine, questa è la soluzione per me al momento. –