对表的约束以限制要存储的记录数

时间:2015-11-22 06:48:52

标签: sql sql-server database

我有一个数据库,有两个表AdsImagesadid表中有一个主键Ads,它是Images表中的外键。

我想在表Images上创建一个约束,adid表中可以存储不超过5 Images

我需要知道调用这种类型的约束以及如何使用SQL Server中的查询来完成此操作。

2 个答案:

答案 0 :(得分:3)

没有constaint来强制执行该规则,但是像下面这样的触发器可以执行:

CREATE TRIGGER Images_not_more_than_five_per_add
ON Images FOR INSERT
AS
DECLARE @RowCount int
SET @RowCount = @@ROWCOUNT
SET NOCOUNT ON
IF @RowCount = 1
BEGIN
    IF (SELECT COUNT(*) FROM Images WHERE Images.addid = (SELECT addid FROM inserted)) > 5
    BEGIN
        RAISERROR('No more than five images per add are allowed', 16, -1)
        ROLLBACK
        RETURN
    END
END
ELSE
BEGIN
    IF EXISTS (
        SELECT *
        FROM
            Images
            INNER JOIN (
                SELECT DISTINCT addid FROM inserted
            ) I ON Images.addid = I.addid
        GROUP BY
            Images.addid
        HAVING COUNT(*) > 5
    )
    BEGIN
        RAISERROR('No more than five images per add are allowed', 16, -1)
        ROLLBACK
        RETURN  
    END
END

答案 1 :(得分:0)

外键约束没有限制子行数的选项。

使用触发器可以实现期望的效果,但是这种约束相对简单,并且可以仅使用声明性约束来实现期望的效果。

创建一个帮助表CheckFiveRows,其列ID包含五行,值为1到5. ID是主键。确保它只包含五行。将列CheckFiveRowID添加到Images表,该表是指向CheckFiveRows.ID的外键。在(AdID, CheckFiveRowID)上添加唯一约束/索引。

表广告

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

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

表格图片

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

<强>测试

填充Ads

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

(2 row(s) affected)

填充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)

尝试为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.

尝试为AdID=2插入6行:

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.