根据主行字段值验证行数
Validate number of rows depending on master row field value
我需要添加一个约束来验证引用 master table 的行数低于 master 行中的值,例如我们有一个 table
master(master_id int pk, max_val int)
和 slave(slave_id int pk, master_id fk ref master(master_id))
(所以 slave 实际上是某种东西的集合),我希望 slave
中的 count(master_id)
是 <= 而不是 max_val
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 服务器告知不允许子查询(sql 服务器 2017)所以...)。
我也读过Check Constraint - Subqueries are not allowed in this context,所以问题是:有没有其他选择(我想避免使用触发器)?
我在 spring 应用程序中使用它与 spring 数据 jpa(和休眠)- 可能有用,但我想在数据库端而不是在应用程序中使用它。
无论如何实体就像:
@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
是一个奴隶(或者更好 - 另一个 table 将被创建,实际上这将是那个奴隶 table)受 slots
值。
所以问题是...
如何限制每个 RoutePart
附加的 ApplicationUser
数量
如果您希望检查约束基于查询,则必须使用用户定义的函数来使用检查约束。
这是一个简单的例子:
表格:
CREATE TABLE dbo.Parent
(
Id int,
MaxNumberOfChildren int NOT NULL
);
CREATE TABLE dbo.Child
(
Id int,
ParentId int
);
用户自定义函数(它所做的只是returnMaxNumberOfChildren
和Child
table中的记录数之间的差异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
table:
ALTER TABLE dbo.Child
ADD CONSTRAINT chk_childCount CHECK (dbo.RestrictNumbrOfChildren(ParentId) >= 0);
这基本上就是您所需要的,除非 MaxNumberOfChildren
可以为 null。
在这种情况下,您应该将 ISNULL()
添加到第一个查询,如果 null 表示不允许 children 则使用 0
,或者如果允许则使用 int (2,147,483,647
) 的最大值null 表示对 children 的数量没有限制 - 所以它变成 SELECT ISNULL(MaxNumberOfChildren, 0)...
或 SELECT ISNULL(MaxNumberOfChildren, 2147483647)...
.
为了测试脚本,让我们向 Parent
table:
中插入一些数据
INSERT INTO Parent (Id, MaxNumberOfChildren) VALUES
(1, 3), (2, 2), (3, 1);
并将一些有效数据插入 Child
table:
INSERT INTO Child (Id, ParentId) VALUES
(1, 1), (2, 2);
到目前为止,我们还没有超过允许的最大记录数。现在让我们尝试通过向 Child
table:
插入更多数据来做到这一点
INSERT INTO Child (Id, ParentId) VALUES
(3, 1), (4, 1), (5, 1);
现在,此插入语句将失败并显示错误消息:
The INSERT statement conflicted with the CHECK constraint "chk_childCount". The conflict occurred in database "<your database name here>", table "dbo.Child", column 'ParentId'.
我需要添加一个约束来验证引用 master table 的行数低于 master 行中的值,例如我们有一个 table
master(master_id int pk, max_val int)
和 slave(slave_id int pk, master_id fk ref master(master_id))
(所以 slave 实际上是某种东西的集合),我希望 slave
中的 count(master_id)
是 <= 而不是 max_val
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 服务器告知不允许子查询(sql 服务器 2017)所以...)。
我也读过Check Constraint - Subqueries are not allowed in this context,所以问题是:有没有其他选择(我想避免使用触发器)?
我在 spring 应用程序中使用它与 spring 数据 jpa(和休眠)- 可能有用,但我想在数据库端而不是在应用程序中使用它。 无论如何实体就像:
@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
是一个奴隶(或者更好 - 另一个 table 将被创建,实际上这将是那个奴隶 table)受 slots
值。
所以问题是...
如何限制每个 RoutePart
ApplicationUser
数量
如果您希望检查约束基于查询,则必须使用用户定义的函数来使用检查约束。
这是一个简单的例子:
表格:
CREATE TABLE dbo.Parent
(
Id int,
MaxNumberOfChildren int NOT NULL
);
CREATE TABLE dbo.Child
(
Id int,
ParentId int
);
用户自定义函数(它所做的只是returnMaxNumberOfChildren
和Child
table中的记录数之间的差异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
table:
ALTER TABLE dbo.Child
ADD CONSTRAINT chk_childCount CHECK (dbo.RestrictNumbrOfChildren(ParentId) >= 0);
这基本上就是您所需要的,除非 MaxNumberOfChildren
可以为 null。
在这种情况下,您应该将 ISNULL()
添加到第一个查询,如果 null 表示不允许 children 则使用 0
,或者如果允许则使用 int (2,147,483,647
) 的最大值null 表示对 children 的数量没有限制 - 所以它变成 SELECT ISNULL(MaxNumberOfChildren, 0)...
或 SELECT ISNULL(MaxNumberOfChildren, 2147483647)...
.
为了测试脚本,让我们向 Parent
table:
INSERT INTO Parent (Id, MaxNumberOfChildren) VALUES
(1, 3), (2, 2), (3, 1);
并将一些有效数据插入 Child
table:
INSERT INTO Child (Id, ParentId) VALUES
(1, 1), (2, 2);
到目前为止,我们还没有超过允许的最大记录数。现在让我们尝试通过向 Child
table:
INSERT INTO Child (Id, ParentId) VALUES
(3, 1), (4, 1), (5, 1);
现在,此插入语句将失败并显示错误消息:
The INSERT statement conflicted with the CHECK constraint "chk_childCount". The conflict occurred in database "<your database name here>", table "dbo.Child", column 'ParentId'.