วิธี จำกัด จำนวนแถวสูงสุดในตารางให้เหลือเพียง 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
เช่นเดียวกับคำอธิบายสำหรับสาเหตุที่วิธีการดั้งเดิมของคุณใช้งานไม่ได้: คุณใช้ทริกเกอร์แทนที่แทนซึ่งหมายความว่ารหัสของคุณจะทำงานแทนที่จะใช้คำสั่งแทรก ดังนั้นเพื่อให้การแทรกเกิดขึ้นคุณต้องรวมไว้อย่างชัดเจนเป็นส่วนหนึ่งของทริกเกอร์
สกอตต์ M

คำตอบ:


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)
เมื่อรวมกันข้อ จำกัด ที่เกือบตรงกันข้ามทั้งสองจะ จำกัด จำนวนของแถวเป็นศูนย์หรือหนึ่ง


บน DBMS แบบสวม (ไม่มีการใช้งาน SQL ในปัจจุบันอนุญาตให้มีการสร้างนี้) ที่อนุญาตให้มีคีย์หลักซึ่งประกอบด้วย 0 คอลัมน์นี่จะเป็นวิธีแก้ปัญหาเช่นกัน:

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

24

คุณสามารถกำหนด ID เป็นคอลัมน์ที่คำนวณได้ซึ่งประเมินค่าเป็นค่าคงที่และประกาศคอลัมน์นั้นว่าไม่ซ้ำกัน:

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

ดูเหมือนว่ามีข้อกำหนดแปลก ๆ นิดหน่อย แต่ ho-hum :) คุณสามารถมีข้อ จำกัด บนโต๊ะแล้วอนุญาตเฉพาะการอัปเดต (ไม่มีการแทรกหรือลบ) ไปที่ตารางใช่หรือไม่

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

เป็นบิตของวิธีแฮ็คที่จะทำมันจะไม่ดีกว่าที่จะบังคับใช้การเปลี่ยนแปลงการกำหนดค่าผ่านขั้นตอนการจัดเก็บที่สามารถจัดการกับตรรกะนี้ทั้งหมดสำหรับคุณ


2
เพียงให้แน่ใจว่าไม่มีใครสามารถลบออกจากตาราง หากมีคนลบแล้วลองใส่ใหม่อีกครั้งมันจะพยายามแทรกด้วย 2 ซึ่งจะไม่อนุญาต
Mat

5
สิ่งนี้ไม่ได้เป็นการห้ามIDให้มีค่า0หรือค่าลบ และเช่นเดียวกับ @Mat points มันจะล้มเหลวหากคุณพยายามแทรกแถวอื่นหากลบแถวแรก
ypercubeᵀᴹ

2
ในฐานะที่เป็น "ข้อกำหนดที่แปลก" ฉันชอบที่จะใช้ตารางแบบแถวเดียวสำหรับการตั้งค่าการกำหนดค่าแทนการออกแบบEAV ที่ดูเหมือนทั่วไป ข้อดีของการเป็นแบบเดิมคือสามารถสร้างคอลัมน์ด้วยชนิดข้อมูลที่เหมาะสมและเพิ่มข้อ จำกัด ที่เหมาะสม (ง่ายขึ้น)
Kenny Evitt

2
บางทีฉันอาจไม่ชัดเจนในความคิดเห็นก่อนหน้าของฉัน ผลข้างเคียงของ"สิ่งนี้ไม่ได้ห้าม ID ให้มีค่าเป็น 0 หรือค่าลบ"คือตารางอาจลงท้ายด้วย 2 แถวหรือมากกว่า คุณสมบัติตัวตนไม่ได้หมายความถึงข้อ จำกัด ที่ไม่ซ้ำกัน
ypercubeᵀᴹ

3
เพื่อแสดงให้เห็นถึงสิ่งที่ @ ypercube with พูดด้วยโซลูชันนี้คุณสามารถทำได้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; หลายครั้งและคุณจะจบลงด้วยตารางหลายแถว
Andriy M
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.