Como limitar o número máximo de linhas em uma tabela para apenas 1

22

Eu tenho uma tabela de configuração no meu banco de dados SQL Server e essa tabela deve ter apenas uma linha. Para ajudar futuros desenvolvedores a entender isso, eu gostaria de impedir que mais de uma linha de dados seja adicionada. Optei por usar um gatilho para isso, como abaixo ...

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

Isso não gera um erro, mas não permite a entrada da primeira linha.

Também existe uma maneira mais eficaz / mais autoexplicativa de limitar o número de linhas que podem ser inseridas em uma tabela para apenas 1, além disso? Estou faltando algum recurso interno do SQL Server?

Dib
fonte
2
Apenas como uma explicação do motivo pelo qual sua abordagem original não estava funcionando: Você usa um gatilho Em vez de, o que significa que seu código é executado em vez da instrução insert. Portanto, para que a inserção ocorra, você deve incluí-la explicitamente como parte do gatilho.
Scott M

Respostas:

52

Essas duas restrições serviriam:

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)
) ;

Você precisa da PRIMARY KEY(ou uma UNIQUErestrição) para que não haja duas linhas com o mesmo IDvalor e a CHECKrestrição para que todas as linhas tenham o mesmo IDvalor (escolhido arbitrariamente 1).
Em conjunto, as duas restrições quase opostas restringem o número de linhas a zero ou uma.


Em um DBMS fictício (nenhuma implementação SQL atual permite essa construção) que permite uma chave primária composta por 0 colunas, isso também seria uma solução:

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

Você pode definir o ID como uma coluna calculada avaliando um valor constante e declarar essa coluna como única:

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

Você também pode usar o gatilho ..

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

    if @tableCount > 50
    begin
        rollback
    end
go
topher
fonte
1

Parece um requisito estranho, mas ho-hum :) Você só pode ter uma restrição na tabela e permitir apenas atualizações (sem inserção ou exclusão) na tabela?

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

No entanto, é uma maneira um tanto hackey de fazer isso, não seria melhor apenas impor alterações na configuração por meio de um procedimento armazenado que pode então lidar com toda essa lógica para você?

Esteira
fonte
2
Apenas garanta que ninguém possa excluir da tabela. Se alguém excluir e tentar reinserir, tentará inserir com uma identidade 2 que não será permitida.
Mat
5
Isso não proíbe que o IDvalor 0seja negativo ou negativo. E como o @Mat aponta, ele falhará se você tentar inserir outra linha se a primeira for excluída.
precisa saber é o seguinte
2
Por ser um "requisito estranho", prefiro usar uma tabela de linha única para definições de configuração, em vez do design aparentemente mais comum do EAV . A vantagem do primeiro é que as colunas podem ser criadas com um tipo de dados apropriado e restrições apropriadas podem ser adicionadas (mais facilmente).
precisa saber é o seguinte
2
Talvez eu não tenha sido muito claro no meu comentário anterior. Um efeito colateral de "Isso não proíbe que o ID tenha um valor 0 ou negativo" é que a tabela pode terminar com 2 ou mais linhas. A propriedade de identidade não implica restrição exclusiva.
ypercubeᵀᴹ
3
Para ilustrar o que o @ ypercubeᵀᴹ disse, com esta solução, você pode fazer, por exemplo, INSERT INTO dbo.Config DEFAULT VALUES;apenas uma vez, mas pode segui-la SET IDENTITY_INSERT dbo.Config ON; INSERT INTO dbo.Config (ID) VALUES (0); SET IDENTITY_INSERT dbo.Config OFF; várias vezes, e você terminará com uma tabela de várias linhas.
Andriy M