根据主行字段值验证行数

问题描述 投票:0回答:1

我需要添加一个约束来验证引用主表的行数低于主行中的值,例如我们有一个表master(master_id int pk, max_val int)slave(slave_id int pk, master_id fk ref master(master_id))(所以奴隶实际上是一个东西的集合),我想在count(master_id)中的slave这个max_val是<= than master_id。我有一个约束

 constraint NO_MORE_PASS check ((select count(head_id) from parts p where 
 p.head_id = head_id) <= (select max_val from head where id = head_id));

(不确定它是否正确,但是SQL Server告诉不允许子查询(sql server 2017)所以......)。

我也读过Check Constraint - Subqueries are not allowed in this context,所以问题是:还有其他选择(我想避免使用触发器)?

我在spring应用程序中使用spring spring jpa(和hibernate) - 可能很有用,但想在db端而不是app中创建它。尽管如此,实体却是这样的:

@Entity
@Table(name = "route_parts")
data class RoutePart(
  @Id
  @Column(name = "route_part_id")
  @GeneratedValue(strategy = GenerationType.AUTO)
  var id: Long? = null,
//...

  @Column(nullable = false)
  var slots: Int? = null,

  @ManyToMany(fetch = FetchType.LAZY)
  @JoinTable(name = "route_part_passengers",
    joinColumns = [(JoinColumn(name = "route_part_id"))],
    inverseJoinColumns = [(JoinColumn(name = "user_id"))]
  )
  var passengers: Set<ApplicationUser> = setOf()
) 

在那种情况下,ApplicationUser是一个奴隶(或更好 - 另一个表将被创建,实际上这将是那个奴隶表)受slots值的限制。

所以问题是......

如何实现限制每个ApplicationUser附加的RoutePart数量

sql-server hibernate tsql check-constraints
1个回答
1
投票

如果希望检查约束基于查询,则必须使用用户定义的函数来使用检查约束。 这是一个简单的例子:

表:

CREATE TABLE dbo.Parent
(
    Id int,
    MaxNumberOfChildren int NOT NULL
);

CREATE TABLE dbo.Child
(
    Id int,
    ParentId int
);

用户定义的函数(它所做的就是返回MaxNumberOfChildrenChild表中记录数量相同的ParentId之间的差异):

CREATE FUNCTION dbo.RestrictNumbrOfChildren
(
    @ParentId int
)
RETURNS int
AS
BEGIN

    RETURN 
        (
            SELECT MaxNumberOfChildren
            FROM dbo.Parent
            WHERE Id = @ParentId
        )
        - 
        (
            SELECT COUNT(Id) 
            FROM dbo.Child
            WHERE ParentId = @ParentId
        )
END;

将检查约束添加到Child表:

ALTER TABLE dbo.Child
    ADD CONSTRAINT chk_childCount CHECK (dbo.RestrictNumbrOfChildren(ParentId) >= 0);

除非MaxNumberOfChildren可以为空,否则这基本上就是你所需要的。 在这种情况下,您应该将ISNULL()添加到第一个查询,如果null表示不允许子项,则为0;如果null表示对子项数没有限制,则为int(2,147,483,647)的最大值 - 因此它变为SELECT ISNULL(MaxNumberOfChildren, 0)...SELECT ISNULL(MaxNumberOfChildren, 2147483647)...

要测试脚本,让我们在Parent表中插入一些数据:

INSERT INTO Parent (Id, MaxNumberOfChildren) VALUES
(1, 3), (2, 2), (3, 1);

并将一些有效数据插入Child表:

INSERT INTO Child (Id, ParentId) VALUES
(1, 1), (2, 2);

到目前为止,我们还没有超过允许的最大记录数。现在让我们尝试通过向Child表中插入更多数据来做到这一点:

INSERT INTO Child (Id, ParentId) VALUES
(3, 1), (4, 1), (5, 1);

现在,此insert语句将失败并显示错误消息:

INSERT语句与CHECK约束“chk_childCount”冲突。冲突发生在数据库“<您的数据库名称>”,表“dbo.Child”,列“ParentId”中。

You can see a live demo on rextester.

© www.soinside.com 2019 - 2024. All rights reserved.