Cara membatasi jumlah maksimum baris dalam tabel menjadi hanya 1


22

Saya memiliki tabel konfigurasi di database SQL Server saya dan tabel ini seharusnya hanya memiliki satu baris. Untuk membantu pengembang di masa depan memahami hal ini, saya ingin mencegah lebih dari satu baris data ditambahkan. Saya telah memilih untuk menggunakan pemicu untuk ini, seperti di bawah ini ...

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

Ini tidak menimbulkan kesalahan tetapi tidak mengizinkan baris pertama masuk.

Juga adakah cara yang lebih efektif / lebih menjelaskan diri sendiri untuk membatasi jumlah baris yang dapat dimasukkan ke dalam tabel menjadi hanya 1, daripada ini? Apakah saya kehilangan fitur SQL Server bawaan?


2
Sama seperti penjelasan mengapa pendekatan asli Anda tidak berfungsi: Anda menggunakan pemicu Alih-alih, yang berarti kode Anda dijalankan alih-alih pernyataan sisipan. Jadi agar penyisipan terjadi, Anda harus secara eksplisit memasukkannya sebagai bagian dari pemicu.
Scott M

Jawaban:


52

Dua kendala ini akan membuat:

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

Anda memerlukan keduanya PRIMARY KEY(atau UNIQUEbatasan) sehingga tidak ada dua baris yang memiliki nilai yang sama ID, dan CHECKkendala sehingga semua baris memiliki nilai yang sama ID(dipilih secara sewenang-wenang 1).
Secara kombinasi, dua kendala yang hampir berseberangan membatasi jumlah baris menjadi nol atau satu.


Pada DBMS fiksi (tidak ada implementasi SQL saat ini memungkinkan konstruksi ini) yang memungkinkan kunci primer yang terdiri dari 0 kolom, ini juga akan menjadi solusi:

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

24

Anda bisa mendefinisikan ID sebagai kolom yang dihitung yang mengevaluasi nilai konstan, dan menyatakan kolom itu unik:

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

9

Anda juga dapat menggunakan pemicu ..

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

    if @tableCount > 50
    begin
        rollback
    end
go

1

Tampaknya sedikit persyaratan aneh tapi ho-hum :) Anda bisa saja memiliki kendala di atas meja dan kemudian hanya memperbolehkan pembaruan (tanpa memasukkan atau menghapus) ke tabel?

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

Ini sedikit cara hackey untuk melakukannya, bukankah lebih baik hanya memaksakan perubahan pada konfigurasi melalui prosedur tersimpan yang kemudian dapat menangani semua logika ini untuk Anda?


2
Pastikan tidak ada yang bisa menghapus dari tabel. Jika seseorang menghapus dan kemudian mencoba memasukkannya kembali, ia akan mencoba memasukkannya dengan identitas 2 yang tidak diizinkan.
Mat

5
Ini tidak melarang IDuntuk memiliki nilai 0atau nilai negatif. Dan sebagai @Mat poin, itu akan gagal jika Anda mencoba memasukkan baris lain jika yang pertama dihapus.
ypercubeᵀᴹ

2
Adapun menjadi "persyaratan aneh", saya lebih suka menggunakan tabel baris tunggal untuk pengaturan konfigurasi, daripada desain EAV yang tampaknya lebih umum . Keuntungan dari yang pertama adalah bahwa kolom dapat dibuat dengan tipe data yang sesuai dan kendala yang tepat dapat ditambahkan (lebih mudah).
Kenny Evitt

2
Mungkin saya tidak begitu jelas dalam komentar saya sebelumnya. Efek samping dari "Ini tidak melarang ID memiliki nilai 0 atau negatif" adalah bahwa tabel dapat diakhiri dengan 2 atau lebih baris. Properti identitas tidak menyiratkan kendala unik.
ypercubeᵀᴹ

3
Untuk mengilustrasikan apa yang dikatakan @ ypercubeᵀᴹ, dengan solusi ini Anda dapat melakukan mis INSERT INTO dbo.Config DEFAULT VALUES;hanya sekali, tetapi Anda dapat mengikutinya SET IDENTITY_INSERT dbo.Config ON; INSERT INTO dbo.Config (ID) VALUES (0); SET IDENTITY_INSERT dbo.Config OFF; berkali-kali, dan Anda akan berakhir dengan beberapa tabel baris.
Andriy M
Dengan menggunakan situs kami, Anda mengakui telah membaca dan memahami Kebijakan Cookie dan Kebijakan Privasi kami.
Licensed under cc by-sa 3.0 with attribution required.