Як обмежити максимальну кількість рядків у таблиці лише 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
Як пояснення того, чому ваш оригінальний підхід не працював: ви використовуєте тригер Name Of, а це означає, що ваш код запускається замість оператора insert. Тож для того, щоб вставка трапилася, ви повинні явно включити її як частину тригера.
Скотт М

Відповіді:


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

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
Можливо, я не був дуже зрозумілий у своєму попередньому коментарі. Побічним ефектом "Це не забороняє ідентифікатору мати значення 0 або негативне" полягає в тому, що таблиця може закінчуватися 2 або більше рядками. Властивість ідентичності не передбачає унікального обмеження.
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; багато разів, і ви отримаєте таблицю з декількома рядками.
Андрій М
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.