So beschränken Sie die maximale Anzahl von Zeilen in einer Tabelle auf 1

22

Ich habe eine Konfigurationstabelle in meiner SQL Server-Datenbank und diese Tabelle sollte immer nur eine Zeile enthalten. Damit zukünftige Entwickler dies besser verstehen, möchte ich verhindern, dass mehr als eine Datenzeile hinzugefügt wird. Ich habe mich dafür entschieden, einen Auslöser zu verwenden, wie unten dargestellt ...

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

Dies löst keinen Fehler aus, lässt jedoch nicht zu, dass die erste Zeile eingegeben wird.

Gibt es auch eine effektivere / selbsterklärendere Möglichkeit, die Anzahl der Zeilen, die in eine Tabelle eingefügt werden können, auf nur 1 zu beschränken? Fehlt mir eine integrierte SQL Server-Funktion?

Dib
quelle
2
Nur als Erklärung, warum Ihr ursprünglicher Ansatz nicht funktioniert hat: Sie verwenden einen Statt-Trigger, dh, Ihr Code wird anstelle der insert-Anweisung ausgeführt. Damit das Einfügen erfolgen kann, müssen Sie es explizit als Teil des Triggers einschließen.
Scott M

Antworten:

52

Diese beiden Einschränkungen würden ausreichen:

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

Sie benötigen sowohl die PRIMARY KEY(oder eine UNIQUEEinschränkung), damit keine zwei Zeilen den gleichen IDWert haben, als auch die CHECKEinschränkung, damit alle Zeilen den gleichen IDWert haben (willkürlich ausgewählt 1).
In Kombination begrenzen die beiden fast entgegengesetzten Einschränkungen die Anzahl der Zeilen entweder auf Null oder auf Eins.


Auf einem fiktiven DBMS (keine aktuelle SQL-Implementierung erlaubt diese Konstruktion), das einen Primärschlüssel aus 0 Spalten erlaubt, wäre dies auch eine Lösung:

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

Sie können die ID als berechnete Spalte definieren, die einen konstanten Wert ergibt, und diese Spalte als eindeutig deklarieren:

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

Sie können auch den Auslöser verwenden.

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

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

Scheint ein bisschen seltsam, ist aber zu laut :) Sie könnten nur eine Einschränkung für die Tabelle haben und dann nur Aktualisierungen (kein Einfügen oder Löschen) für die Tabelle zulassen?

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

Es ist ein bisschen hackig, das zu tun. Wäre es nicht besser, Änderungen an der Konfiguration durch eine gespeicherte Prozedur zu erzwingen, die dann diese ganze Logik für Sie handhaben kann?

Matte
quelle
2
Stellen Sie einfach sicher, dass niemand aus der Tabelle löschen kann. Wenn jemand löscht und dann versucht, es erneut einzufügen, wird versucht, es mit einer Identität von 2 einzufügen, die es nicht zulässt.
Mat
5
Dies verbietet nicht ID, einen Wert von 0oder einen negativen zu haben. Und wie @Mat zeigt, schlägt es fehl, wenn Sie versuchen, eine weitere Zeile einzufügen, wenn die erste gelöscht wird.
ypercubeᵀᴹ
2
Als "merkwürdige Anforderung" bevorzuge ich die Verwendung einer einzeiligen Tabelle für Konfigurationseinstellungen anstelle des scheinbar allgemeineren EAV- Designs. Ersteres hat den Vorteil, dass Spalten mit einem geeigneten Datentyp erstellt und entsprechende Einschränkungen hinzugefügt werden können (einfacher).
Kenny Evitt
2
Vielleicht war ich in meinem vorherigen Kommentar nicht sehr klar. Ein Nebeneffekt von "Dies verbietet der ID nicht, einen Wert von 0 oder einen negativen zu haben" ist, dass die Tabelle mit 2 oder mehr Zeilen enden könnte. Die Identitätseigenschaft impliziert keine eindeutige Einschränkung.
ypercubeᵀᴹ
3
Um zu veranschaulichen, was @ ypercubeᵀᴹ gesagt hat, können Sie mit dieser Lösung z. B. INSERT INTO dbo.Config DEFAULT VALUES;nur einmal vorgehen , aber Sie können ihr SET IDENTITY_INSERT dbo.Config ON; INSERT INTO dbo.Config (ID) VALUES (0); SET IDENTITY_INSERT dbo.Config OFF; mehrere Male folgen , und Sie erhalten eine mehrzeilige Tabelle.
Andriy M