Cómo limitar el número máximo de filas en una tabla a solo 1


22

Tengo una tabla de configuración en mi base de datos de SQL Server y esta tabla solo debería tener una fila. Para ayudar a los futuros desarrolladores a comprender esto, me gustaría evitar que se agregue más de una fila de datos. He optado por usar un disparador para esto, como se muestra a continuación ...

ALTER TRIGGER OnlyOneConfigRow
    ON [dbo].[Configuration]
    INSTEAD OF INSERT
AS
BEGIN
    DECLARE @HasZeroRows BIT;
    SELECT  @HasZeroRows = CASE
        WHEN COUNT (Id) = 0 THEN 1
        ELSE 0
    END
    FROM
        [dbo].[Configuration];

    IF EXISTS(SELECT [Id] FROM inserted) AND @HasZeroRows = 0
    BEGIN
        RAISERROR ('You should not add more than one row into the config table. ', 16, 1)    
    END
END

Esto no arroja un error pero no permite que entre la primera fila.

Además, ¿hay una forma más efectiva / más autoexplicativa de limitar el número de filas que se pueden insertar en una tabla a solo 1, que esto? ¿Me falta alguna función incorporada de SQL Server?


2
Solo como una explicación de por qué su enfoque original no estaba funcionando: utiliza un activador En lugar de, lo que significa que su código se ejecuta en lugar de la instrucción de inserción. Entonces, para que ocurra la inserción, debe incluirla explícitamente como parte del disparador.
Scott M

Respuestas:


52

Estas dos restricciones harían:

CREATE TABLE dbo.Configuration
( ConfigurationID TINYINT NOT NULL DEFAULT 1,
  -- the rest of the columns
  CONSTRAINT Configuration_PK 
    PRIMARY KEY (ConfigurationID),
  CONSTRAINT Configuration_OnlyOneRow 
    CHECK (ConfigurationID = 1)
) ;

Necesita tanto la PRIMARY KEY(o una UNIQUErestricción) para que no haya dos filas con el mismo IDvalor, como la CHECKrestricción para que todas las filas tengan el mismo IDvalor (elegido arbitrariamente para 1).
En combinación, las dos restricciones casi opuestas restringen el número de filas a cero o uno.


En un DBMS ficticio (ninguna implementación SQL actual permite esta construcción) que permita una clave primaria que consta de 0 columnas, esta sería una solución también:

CREATE TABLE dbo.Configuration
( -- no ConfigurationID needed at all
  -- the rest of the columns
  CONSTRAINT Configuration_PK 
    PRIMARY KEY ()                -- 0 columns!
) ;

24

Puede definir la ID como una columna calculada que evalúa un valor constante y declarar que esa columna es única:

CREATE TABLE dbo.Configuration
(
  ID AS CAST(1 AS tinyint),  -- or: AS bit
  ...  -- other columns
  CONSTRAINT UQ_Configuration_ID UNIQUE (ID)
);

9

También puedes usar el gatillo.

create trigger LimitTable
on YourTableToLimit
after insert
as
    declare @tableCount int
    select @tableCount = Count(*)
    from YourTableToLimit

    if @tableCount > 50
    begin
        rollback
    end
go

1

Parece un requisito un poco extraño, pero aburrido :) ¿Podría tener una restricción en la tabla y luego solo permitir actualizaciones (sin insertar o eliminar) en la tabla?

CREATE TABLE dbo.Config (
    ID INT identity(1,1), 
    CONFIGURATION VARCHAR(MAX),
    constraint ck_limitrows CHECK (ID <=1) 
    );

Sin embargo, es una forma un poco hackeadora de hacerlo, ¿no sería mejor simplemente imponer cambios en la configuración a través de un procedimiento almacenado que luego puede manejar toda esta lógica por usted?


2
Solo asegúrese de que nadie pueda eliminar de la tabla. Si alguien elimina e intenta volver a insertarlo, intentará insertarlo con una identidad de 2 que no permitirá.
Mat

55
Esto no prohíbe IDque tenga un valor 0negativo o negativo. Y como apunta @Mat, fallará si intenta insertar otra fila si se elimina la primera.
ypercubeᵀᴹ

2
En cuanto a ser un "requisito extraño", prefiero usar una tabla de una sola fila para los ajustes de configuración, en lugar del diseño EAV aparentemente más común . La ventaja de la primera es que las columnas se pueden crear con un tipo de datos apropiado y se pueden agregar restricciones apropiadas (más fácilmente).
Kenny Evitt

2
Quizás no estaba muy claro en mi comentario anterior. Un efecto secundario de "Esto no prohíbe que la ID tenga un valor de 0 o uno negativo" es que la tabla podría terminar con 2 o más filas. La propiedad de identidad no implica una restricción única.
ypercubeᵀᴹ

3
Para ilustrar lo que dijo @ ypercubeᵀᴹ, con esta solución puede hacer, por ejemplo, INSERT INTO dbo.Config DEFAULT VALUES;solo una vez, pero puede seguirla SET IDENTITY_INSERT dbo.Config ON; INSERT INTO dbo.Config (ID) VALUES (0); SET IDENTITY_INSERT dbo.Config OFF; muchas veces y terminará con una tabla de varias filas.
Andriy M
Al usar nuestro sitio, usted reconoce que ha leído y comprende nuestra Política de Cookies y Política de Privacidad.
Licensed under cc by-sa 3.0 with attribution required.