Come limitare il numero massimo di righe in una tabella a solo 1


22

Ho una tabella di configurazione nel mio database SQL Server e questa tabella dovrebbe avere solo una riga. Per aiutare i futuri sviluppatori a capirlo, vorrei impedire l'aggiunta di più di una riga di dati. Ho scelto di utilizzare un trigger per questo, come di seguito ...

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

Questo non genera un errore ma non consente alla prima riga di entrare.

C'è anche un modo più efficace / più autoesplicativo di limitare il numero di righe che possono essere inserite in una tabella a solo 1, rispetto a questo? Mi manca qualche funzionalità di SQL Server integrata?


2
Proprio come una spiegazione del perché il tuo approccio originale non funzionava: usi un trigger Invece di, il che significa che il tuo codice viene eseguito invece dell'istruzione insert. Pertanto, affinché si verifichi l'inserimento, è necessario includerlo esplicitamente come parte del trigger.
Scott M,

Risposte:


52

Questi due vincoli farebbero:

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

È necessario sia il PRIMARY KEY(o un UNIQUEvincolo), quindi non ci sono due righe con lo stesso IDvalore, sia il CHECKvincolo in modo che tutte le righe abbiano lo stesso IDvalore (scelto arbitrariamente 1).
In combinazione, i due vincoli quasi opposti limitano il numero di righe a zero o uno.


Su un DBMS fittizio (nessuna implementazione SQL corrente consente questa costruzione) che consente una chiave primaria composta da 0 colonne, anche questa sarebbe una soluzione:

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

24

È possibile definire l'ID come una colonna calcolata che valuta un valore costante e dichiarare unica quella colonna:

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

9

Puoi anche usare il grilletto ..

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

    if @tableCount > 50
    begin
        rollback
    end
go

1

Sembra un po 'strano ma ho-hum :) Potresti avere un vincolo sulla tabella e consentire solo gli aggiornamenti (nessun inserimento o eliminazione) alla tabella?

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

È un modo un po 'complicato per farlo, non sarebbe meglio applicare semplicemente le modifiche alla configurazione attraverso una procedura memorizzata che può quindi gestire tutta questa logica per te?


2
Assicurati solo che nessuno possa cancellare dalla tabella. Se qualcuno elimina e quindi tenta di reinserirlo, proverà a inserire un'identità di 2 che non consentirà.
Mat,

5
Ciò non proibisce IDdi avere un valore 0o uno negativo. E come indica @Mat, fallirà se si tenta di inserire un'altra riga se la prima viene eliminata.
ypercubeᵀᴹ

2
Per quanto riguarda il fatto di essere un "requisito dispari", preferisco utilizzare una tabella a riga singola per le impostazioni di configurazione, anziché il design EAV apparentemente più comune . Il vantaggio del primo è che le colonne possono essere create con un tipo di dati appropriato e possono essere aggiunti vincoli appropriati (più facilmente).
Kenny Evitt,

2
Forse non ero molto chiaro nel mio commento precedente. Un effetto collaterale di "Questo non impedisce all'ID di avere un valore pari a 0 o uno negativo" è che la tabella potrebbe terminare con 2 o più righe. La proprietà identity non implica un vincolo univoco.
ypercubeᵀᴹ

3
Per illustrare ciò che ha detto @ ypercubeᵀᴹ, con questa soluzione puoi fare ad esempio INSERT INTO dbo.Config DEFAULT VALUES;solo una volta, ma puoi seguirlo con SET IDENTITY_INSERT dbo.Config ON; INSERT INTO dbo.Config (ID) VALUES (0); SET IDENTITY_INSERT dbo.Config OFF; molte volte e finirai con una tabella a più righe.
Andriy M,
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.