DBMS: MS SQL Server 2005, Standardrestricción únicos dentro de un grupo de registros en los que algún valor es el mismo
me gustaría hacer una restricción de tabla para tener sólo un registro tiene un valor particular dentro de una subconjunto de la tabla (donde las filas comparten un valor en una columna en particular). es posible?
Ejemplo: tengo registros en myTable que tienen una clave externa no único (fk1), y una columna de bits denominado isPrimary para marcar que éste en particular debe ser utilizado por nuestra aplicación de una lógica especial.
en abstracto, que se parece a esto:
myTable
-------------
pk1 (int, not null)
name (varchar(50), null)
fk1 (int, not null)
isPrimary (bit, not null)
que quieren asegurarse de que no hay una y sólo una registro con la bandera isPrimary establecido en 1, para cada valor único de fk1.
Datos ejemplo: Esto debería ser legal:
pk1 name fk1 isPrimary
---- ----- ----- ----------
1 Bill 111 1
2 Tom 111 0
3 Dick 222 1
4 Harry 222 0
Pero esto debe no ser (más de uno, donde fk = 111):
pk1 name fk1 isPrimary
---- ----- ----- ----------
1 Bill 111 1
2 Tom 111 1
3 Dick 222 1
4 Harry 222 0
Y tampoco se debe este (ninguno donde fk = 222):
pk1 name fk1 isPrimary
---- ----- ----- ----------
1 Bill 111 1
2 Tom 111 0
3 Dick 222 0
4 Harry 222 0
Es Hay una manera de hacer esto con una restricción de tabla?
ACTUALIZACIÓN he ido con la respuesta de Martin Smith por ahora, aunque voy a estar empujando para refactor de JohnFx en una próxima versión, ya que es la mejor solución a largo plazo. Sin embargo, quería publicar mi UDF actualizado basado en la respuesta de Raze2dust, en caso de que los futuros lectores decidan que se ajusta mejor a sus necesidades.
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;
Cambios:
- usados @tempTable en lugar de
TempTable como lo requiere la UDF
- pasaron @ fk1 como un parámetro de modo que pueda (en la memoria v escritos en el disco.) seleccione para unicidad dentro de un grupo de valores fk1.
- complicado tuvieron que pasar también isPrimary aunque no es necesario que la lógica de la función , de lo contrario el optimizador SQL2005 no se ejecutará la restricción de comprobación cuando isPrimary es actualizada.
Aunque la solución de JohnFx es la mejor solución a largo plazo, esta es la solución para mí en este momento. –