Cách giới hạn số lượng hàng tối đa trong một bảng chỉ còn 1


22

Tôi có một bảng cấu hình trong cơ sở dữ liệu SQL Server của mình và bảng này chỉ nên có một hàng. Để giúp các nhà phát triển trong tương lai hiểu điều này, tôi muốn ngăn chặn nhiều hơn một hàng dữ liệu được thêm vào. Tôi đã chọn sử dụng một kích hoạt cho việc này, như dưới đây ...

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

Điều này không gây ra lỗi nhưng không cho phép hàng đầu tiên đi vào.

Ngoài ra, có cách nào hiệu quả hơn / tự giải thích hơn về việc giới hạn số lượng hàng có thể được chèn vào một bảng chỉ còn 1, hơn thế này không? Tôi có thiếu tính năng SQL Server tích hợp nào không?


2
Giống như một lời giải thích cho lý do tại sao cách tiếp cận ban đầu của bạn không hoạt động: Bạn sử dụng kích hoạt Thay vì kích hoạt, có nghĩa là mã của bạn được chạy thay vì câu lệnh chèn. Vì vậy, để chèn vào xảy ra, bạn phải bao gồm nó một cách rõ ràng như là một phần của kích hoạt.
Scott M

Câu trả lời:


52

Hai ràng buộc này sẽ làm:

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

Bạn cần cả hai PRIMARY KEY(hoặc một UNIQUEràng buộc) để không có hai hàng nào có cùng IDgiá trị và CHECKràng buộc để tất cả các hàng có cùng IDgiá trị (được chọn tùy ý 1).
Kết hợp lại, hai ràng buộc gần như ngược nhau giới hạn số lượng hàng là 0 hoặc 1.


Trên một DBMS hư cấu (không có triển khai SQL hiện tại nào cho phép xây dựng này) cho phép khóa chính gồm 0 cột, đây cũng là một giải pháp:

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

24

Bạn có thể định nghĩa ID là một cột được tính toán đánh giá thành một giá trị không đổi và khai báo cột đó là duy nhất:

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

9

Bạn cũng có thể sử dụng kích hoạt ..

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

    if @tableCount > 50
    begin
        rollback
    end
go

1

Có vẻ hơi yêu cầu kỳ quặc nhưng ho-hum :) Bạn chỉ có thể có một ràng buộc trên bảng và sau đó chỉ cho phép cập nhật (không chèn hoặc xóa) vào bảng?

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

Mặc dù đó là một cách hackey để làm điều đó, nhưng sẽ tốt hơn nếu chỉ thực thi các thay đổi đối với cấu hình thông qua một thủ tục được lưu trữ để sau đó có thể xử lý tất cả logic này cho bạn?


2
Chỉ cần đảm bảo không ai có thể xóa khỏi bảng. Nếu ai đó xóa và sau đó cố gắng chèn lại, nó sẽ cố gắng chèn với danh tính là 2 mà nó sẽ không cho phép.
Mat

5
Điều này không cấm IDcó giá trị 0hoặc âm. Và như @Mat điểm, nó sẽ thất bại nếu bạn cố chèn một hàng khác nếu hàng đầu tiên bị xóa.
ypercubeᵀᴹ

2
Đối với "yêu cầu kỳ lạ", tôi thích sử dụng bảng một hàng cho các cài đặt cấu hình, thay vì thiết kế EAV dường như phổ biến hơn . Ưu điểm của trước đây là các cột có thể được tạo bằng một kiểu dữ liệu phù hợp và các ràng buộc thích hợp có thể được thêm vào (dễ dàng hơn).
Kenny Evitt

2
Có lẽ tôi đã không rõ ràng trong bình luận trước đây của tôi. Một tác dụng phụ của "Điều này không cấm ID có giá trị 0 hoặc âm" là bảng có thể kết thúc với 2 hàng trở lên. Các tài sản nhận dạng không ngụ ý ràng buộc duy nhất.
ypercubeᵀᴹ

3
Để minh họa những gì @ ypercubeᵀᴹ đã nói, với giải pháp này, bạn có thể thực hiện, ví dụ INSERT INTO dbo.Config DEFAULT VALUES;chỉ một lần, nhưng bạn có thể theo dõi nó SET IDENTITY_INSERT dbo.Config ON; INSERT INTO dbo.Config (ID) VALUES (0); SET IDENTITY_INSERT dbo.Config OFF; nhiều lần và bạn sẽ kết thúc với một bảng nhiều hàng.
Andriy M
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.