Как ограничить максимальное количество строк в таблице до 1

22

У меня есть таблица конфигурации в моей базе данных SQL Server, и эта таблица должна иметь только одну строку. Чтобы помочь будущим разработчикам понять это, я бы хотел предотвратить добавление нескольких строк данных. Я решил использовать триггер для этого, как показано ниже ...

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

Это не выдает ошибку, но не позволяет войти в первую строку.

Также существует ли более эффективный / более понятный способ ограничения числа строк, которые могут быть вставлены в таблицу, до 1, чем этот? Мне не хватает встроенной функции SQL Server?

Диб
источник
2
Просто как объяснение того, почему ваш оригинальный подход не работал: вы используете триггер вместо, что означает, что ваш код запускается вместо оператора вставки. Таким образом, чтобы вставка произошла, вы должны явно включить ее как часть триггера.
Скотт М,

Ответы:

52

Эти два ограничения будут делать:

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

Вам нужно и PRIMARY KEY(или UNIQUEограничение), чтобы никакие две строки не имели одинаковое IDзначение, и CHECKограничение, чтобы все строки имели одинаковое IDзначение (произвольно выбранный 1).
В сочетании два почти противоположных ограничения ограничивают количество строк либо нулем, либо единицей.


В вымышленной СУБД (текущая реализация SQL не позволяет такую ​​конструкцию), которая допускает первичный ключ, состоящий из 0 столбцов, это тоже будет решением:

CREATE TABLE dbo.Configuration
( -- no ConfigurationID needed at all
  -- the rest of the columns
  CONSTRAINT Configuration_PK 
    PRIMARY KEY ()                -- 0 columns!
) ;
ypercubeᵀᴹ
источник
24

Вы можете определить идентификатор как вычисляемый столбец с постоянным значением и объявить этот столбец уникальным:

CREATE TABLE dbo.Configuration
(
  ID AS CAST(1 AS tinyint),  -- or: AS bit
  ...  -- other columns
  CONSTRAINT UQ_Configuration_ID UNIQUE (ID)
);
Андрей М
источник
9

Вы также можете использовать триггер ..

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

    if @tableCount > 50
    begin
        rollback
    end
go
Тофер
источник
1

Кажется немного странным требованием, но хо-хум :) Вы могли бы просто иметь ограничение на таблицу и затем разрешать только обновления (без вставки или удаления) таблицы?

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

Хотя это немного хакерский способ, не лучше ли просто принудительно вносить изменения в конфигурацию с помощью хранимой процедуры, которая затем может обработать всю эту логику для вас?

Мат
источник
2
Просто убедитесь, что никто не может удалить из таблицы. Если кто-то удаляет, а затем пытается вставить заново, он попытается вставить с идентификатором 2, что не разрешено.
Мат
5
Это не запрещает IDиметь значение 0или отрицательное. И, как указывает @Mat, произойдет сбой, если вы попытаетесь вставить другую строку, если первая будет удалена.
ypercubeᵀᴹ
2
Что касается «странного требования», я предпочитаю использовать однострочную таблицу для настроек конфигурации, а не, казалось бы, более распространенный дизайн EAV . Преимущество первого состоит в том, что столбцы могут быть созданы с соответствующим типом данных и могут быть добавлены соответствующие ограничения (более легко).
Кенни Эвитт
2
Возможно, я не очень ясно сказал в своем предыдущем комментарии. Побочный эффект «Это не запрещает ID иметь значение 0 или отрицательное значение» - таблица может заканчиваться двумя или более строками. Свойство идентичности не подразумевает уникального ограничения.
ypercubeᵀᴹ
3
Чтобы проиллюстрировать, что сказал @ ypercubeᵀᴹ, с этим решением вы можете сделать, например, INSERT INTO dbo.Config DEFAULT VALUES;один раз, но вы можете выполнить его SET IDENTITY_INSERT dbo.Config ON; INSERT INTO dbo.Config (ID) VALUES (0); SET IDENTITY_INSERT dbo.Config OFF; много раз, и в результате вы получите таблицу из нескольких строк.
Андрей М