Constraint on table to limit number of records to be stored

前端 未结 2 1196
青春惊慌失措
青春惊慌失措 2021-01-12 22:21

I have a database and there are two tables Ads and Images. There is a primary key adid in Ads table which is a foreign ke

2条回答
  •  星月不相逢
    2021-01-12 22:52

    The foreign key constraint doesn't have such option to limit the number of child rows.

    It is possible to achieve the desired effect using a trigger, but this kind of constraint is relatively simple and it is possible to achieve the desired effect using only declarative constraints.

    Create a helper table CheckFiveRows with column ID that contains five rows with values 1 to 5. ID is the primary key. Make sure that it contains only five rows. Add a column CheckFiveRowID to the Images table that is a foreign key pointing to CheckFiveRows.ID. Add unique constraint/index on (AdID, CheckFiveRowID).

    Table Ads

    CREATE TABLE [dbo].[Ads](
        [AdID] [int] NOT NULL,
        [AdData] [nvarchar](50) NOT NULL,
     CONSTRAINT [PK_Ads] PRIMARY KEY CLUSTERED 
    (
        [AdID] ASC
    ))
    

    Table CheckFiveRows

    CREATE TABLE [dbo].[CheckFiveRows](
        [ID] [int] NOT NULL,
     CONSTRAINT [PK_CheckFiveRows] PRIMARY KEY CLUSTERED 
    (
        [ID] ASC
    ))
    GO
    
    INSERT INTO [dbo].[CheckFiveRows] ([ID]) VALUES
    (1),(2),(3),(4),(5);
    

    Table Images

    CREATE TABLE [dbo].[Images](
        [ImageID] [int] NOT NULL,
        [AdID] [int] NOT NULL,
        [CheckFiveRowID] [int] NOT NULL,
        [ImageData] [nvarchar](50) NOT NULL,
     CONSTRAINT [PK_Images] PRIMARY KEY CLUSTERED 
    (
        [ImageID] ASC
    ))
    GO
    
    ALTER TABLE [dbo].[Images]  WITH CHECK 
    ADD  CONSTRAINT [FK_Images_Ads] FOREIGN KEY([AdID])
    REFERENCES [dbo].[Ads] ([AdID])
    GO
    
    ALTER TABLE [dbo].[Images] CHECK CONSTRAINT [FK_Images_Ads]
    GO
    
    ALTER TABLE [dbo].[Images]  WITH CHECK 
    ADD  CONSTRAINT [FK_Images_CheckFiveRows] FOREIGN KEY([CheckFiveRowID])
    REFERENCES [dbo].[CheckFiveRows] ([ID])
    GO
    
    ALTER TABLE [dbo].[Images] CHECK CONSTRAINT [FK_Images_CheckFiveRows]
    GO
    
    CREATE UNIQUE NONCLUSTERED INDEX [IX_CheckFiveRows] ON [dbo].[Images]
    (
        [AdID] ASC,
        [CheckFiveRowID] ASC
    )
    GO
    

    Testing

    Populate Ads:

    INSERT INTO [dbo].[Ads] ([AdID],[AdData]) VALUES
    (1, 'a1'),
    (2, 'a2');
    
    (2 row(s) affected)
    

    Populate Images:

    INSERT INTO [dbo].[Images] ([ImageID],[AdID],[CheckFiveRowID],[ImageData]) VALUES
    (1,1,1,'i1'),
    (2,1,2,'i2'),
    (3,1,3,'i3'),
    (4,1,4,'i4');
    
    (4 row(s) affected)
    

    Try to add two more row for AdID=1:

    INSERT INTO [dbo].[Images] ([ImageID],[AdID],[CheckFiveRowID],[ImageData]) VALUES
    (5,1,5,'i5'),
    (6,1,5,'i6');
    
    Msg 2601, Level 14, State 1, Line 8
    Cannot insert duplicate key row in object 'dbo.Images' with unique index 'IX_CheckFiveRows'. The duplicate key value is (1, 5).
    The statement has been terminated.
    

    Try to insert 6 rows for AdID=2:

    INSERT INTO [dbo].[Images] ([ImageID],[AdID],[CheckFiveRowID],[ImageData]) VALUES
    (11,2,1,'i1'),
    (12,2,2,'i2'),
    (13,2,3,'i3'),
    (14,2,4,'i4'),
    (15,2,5,'i5'),
    (16,2,6,'i6');
    
    Msg 547, Level 16, State 0, Line 13
    The INSERT statement conflicted with the FOREIGN KEY constraint "FK_Images_CheckFiveRows". The conflict occurred in database "AdventureWorks2014", table "dbo.CheckFiveRows", column 'ID'.
    The statement has been terminated.
    

提交回复
热议问题