边缘约束
适用于:SQL Server 2019 (15.x) 及更高版本 Azure SQL 数据库 Azure SQL 托管实例
边缘约束可用于对 SQL Server 图形数据库中的边缘表强制执行数据完整性和特定语义。
边缘约束
默认情况下,边缘表不会为边缘的端点强制执行任何操作。 也就是说,无论何种类型,图形数据库中的边缘都可以将任何节点连接到任何其他节点。
SQL Graph 支持边缘约束,使用户能够向其边缘表添加约束,从而强制执行特定语义,同时保持数据完整性。 将新的边缘添加到具有边缘约束的边缘表时,数据库引擎强制让边缘尝试连接的节点存在于正确的节点表中。 如果有任何边缘引用该节点,则还确保了不会删除该节点。
边缘约束子句
单个边缘约束都由一个或多个边缘约束子句组成。
CONSTRAINT constraint_name CONNECTION (cause1[, clause2...])
- 边缘约束子句是一对节点表名称,由
TO
关键字分隔。 - 边缘约束子句中的第一个表名是边缘关系的 FROM 节点表的名称。
- 边缘约束子句中的第二个表名是边缘关系的 TO 节点表的名称。
- 因此,表名称对指示边缘关系的方向。
- 如前文所述,边缘约束可以包含一个或多个边缘约束子句。
多个约束和子句
- 为同一个边缘表定义的多个边缘约束与
AND
运算符一起使用。 - 在同一个边缘约束中定义的多个边缘约束子句与
OR
运算符一起使用。
请考虑图形中的 Supplier
和 Customer
节点。 每个节点可通过单个共享边缘表与 Product
节点关联:bought
。 bought
边缘表支持 Customer-(bought)->Product
和 Supplier-(bought)->Product
关系类型。 可以通过使用具有多个边缘约束子句的单个边缘约束来完成此操作。
示例
CONSTRAINT EC_BOUGHT CONNECTION (Customer TO Product)
上面的示例显示了一个边缘约束,其中包含一个边缘约束子句。 此约束支持 Customer-(bought)->Product
。 也就是说,将允许插入从 Customer
到 Product
的 bought
边缘关系。 插入任何其他节点组合(如 Supplier-(bought)->Product
),即使它可能描述现实世界中的有效关系,也会失败。
CONSTRAINT EC_BOUGHT CONNECTION (Supplier TO Product, Customer TO Product)
上面的示例定义了一个边缘约束,其中包含两个边缘约束子句。 这些约束子句允许 bought
边缘包含 Supplier-(bought)->Product
或 Customer-(bought)->Product
关系。 在 bought
表中插入任何其他类型的边缘关系会失败。
CONSTRAINT EC_BOUGHT1 CONNECTION (Supplier TO Product)
CONSTRAINT EC_BOUGHT2 CONNECTION (Customer TO Product)
上面的示例显示同一边缘表上的两个约束,每个边界约束指定一个约束子句。 在这种情况下,SQL 只允许同时满足这两个边缘约束子句的插入。 这不可能。 没有可满足这两个边缘约束子句的节点对。 此边缘约束组合使边缘表不可用。
有关可在实际应用场景中使用的多个边缘约束的详细说明,请参阅本页后面的“使用新边缘约束子句在现有边缘表上创建新边缘约束”的示例。
边缘约束的索引
创建边缘约束不会自动在边缘表中的 $from_id
和 $to_id
列上创建相应的索引。 如果拥有点查找查询或 OLTP 工作负载,建议在“$from_id
,$to_id
对上手动创建索引。
ON 删除边缘约束上的引用操作
使用边缘约束上的级联操作,用户可以定义当用户删除给定边缘连接到的节点时,数据库引擎所采取的操作。 可以定义以下引用操作:NO ACTION 在尝试删除具有连接边缘的节点时,数据库引擎引发错误。
CASCADE 从数据库中删除某个节点时,会删除连接边缘。
使用边缘约束
可以使用 Transact-SQL 定义 SQL Server 中的边缘约束。 边缘约束只能在图形边缘表上进行定义。 若要创建、删除或修改边缘约束,必须对表拥有 ALTER 权限。
创建边缘约束
下面几个示例展示了如何对新表或现有表创建边缘约束。
在新边缘表上创建边缘约束
下面的示例对 bought
边缘表创建边缘约束。
-- CREATE node and edge tables
CREATE TABLE Customer
(
ID INTEGER PRIMARY KEY
,CustomerName VARCHAR(100)
)
AS NODE;
GO
CREATE TABLE Product
(
ID INTEGER PRIMARY KEY
,ProductName VARCHAR(100)
)
AS NODE;
GO
CREATE TABLE bought
(
PurchaseCount INT
,CONSTRAINT EC_BOUGHT CONNECTION (Customer TO Product) ON DELETE NO ACTION
)
AS EDGE;
定义对新边缘表的引用操作
以下示例对 bought
边缘表创建边缘约束并定义删除级联引用操作。
-- CREATE node and edge tables
CREATE TABLE Customer
(
ID INTEGER PRIMARY KEY
,CustomerName VARCHAR(100)
)
AS NODE;
GO
CREATE TABLE Product
(
ID INTEGER PRIMARY KEY
,ProductName VARCHAR(100)
)
AS NODE;
GO
CREATE TABLE bought
(
PurchaseCount INT
,CONSTRAINT EC_BOUGHT CONNECTION (Customer TO Product) ON DELETE CASCADE
)
AS EDGE;
将边缘约束添加到现有边缘表
以下示例使用 ALTER TABLE 将边缘约束添加到 bought
边缘表。
-- CREATE node and edge tables
CREATE TABLE Customer
(
ID INTEGER PRIMARY KEY
, CustomerName VARCHAR(100)
)
AS NODE;
CREATE TABLE Product
(
ID INTEGER PRIMARY KEY
, ProductName VARCHAR(100)
)
AS NODE;
GO
CREATE TABLE bought
(
PurchaseCount INT
)
AS EDGE;
GO
ALTER TABLE bought ADD CONSTRAINT EC_BOUGHT1 CONNECTION (Customer TO Product);
对现有边缘表新建边缘约束(其中包含附加边缘约束子句)
以下示例使用 ALTER TABLE
命令,将包含附加边缘约束子句的新边缘约束添加到 bought
边缘表。
-- CREATE node and edge tables
CREATE TABLE Customer
(
ID INTEGER PRIMARY KEY
, CustomerName VARCHAR(100)
)
AS NODE;
GO
CREATE TABLE Supplier
(
ID INTEGER PRIMARY KEY
, SupplierName VARCHAR(100)
)
AS NODE;
GO
CREATE TABLE Product
(
ID INTEGER PRIMARY KEY
, ProductName VARCHAR(100)
)
AS NODE;
GO
CREATE TABLE bought
(
PurchaseCount INT
, CONSTRAINT EC_BOUGHT CONNECTION (Customer TO Product)
)
AS EDGE;
-- Drop the existing edge constraint first and then create a new one.
ALTER TABLE bought DROP CONSTRAINT EC_BOUGHT;
GO
-- User ALTER TABLE to create a new edge constraint.
ALTER TABLE bought ADD CONSTRAINT EC_BOUGHT1 CONNECTION (Customer TO Product, Supplier TO Product);
在以上示例中,EC_BOUGHT1
约束中有两个边缘约束子句,一个用于将 Customer
连接到 Product
,另一个用于将 Supplier
连接到 Product
。 这两个子句都可应用于析取。 即,给定的边缘必须满足这两个子句之一,才能在边缘表中使用。
对现有边缘表创建新的边缘约束(其中包含新边缘约束子句)
以下示例使用 ALTER TABLE
命令,将包含新边缘约束子句的新边缘约束添加到 bought
边缘表。
-- CREATE node and edge tables
CREATE TABLE Customer
(
ID INTEGER PRIMARY KEY
, CustomerName VARCHAR(100)
)
AS NODE;
GO
CREATE TABLE Supplier
(
ID INTEGER PRIMARY KEY
, SupplierName VARCHAR(100)
)
AS NODE;
GO
CREATE TABLE Product
(
ID INTEGER PRIMARY KEY
, ProductName VARCHAR(100)
)
AS NODE;
GO
CREATE TABLE bought
(
PurchaseCount INT,
CONSTRAINT EC_BOUGHT CONNECTION (Customer TO Product)
)
AS EDGE;
GO
在前面的示例中,假设现在还需要通过 bought
边缘表包含 Supplier
到 Product
的关系。 可以尝试添加新的边缘约束:
ALTER TABLE bought ADD CONSTRAINT EC_BOUGHT1 CONNECTION (Supplier TO Product);
但是,添加新的边缘约束并不是正确的解决方案。 我们在 bought
边缘表上创建了两个单独的边缘约束:EC_BOUGHT
和 EC_BOUGHT1
。 这两个边缘约束都具有不同的边缘约束子句。 如果一个边缘表在其上具有多个边缘约束,则给定的边缘表必须满足所有 边缘约束,才能在边缘表中使用它。 由于此处没有任何边缘能够同时满足 EC_BOUGHT
和 EC_BOUGHT1
,因此如果 ALTER TABLE
边缘表中存在任何行,则上述 bought
语句将失败。
要成功创建此边缘约束,需要按照本示例中所示的以下顺序来操作:
-- First, add the desired ("super-set") constraint:
ALTER TABLE bought ADD CONSTRAINT EC_BOUGHT_NEW CONNECTION (Customer TO Product, Supplier TO Product);
GO
-- Then, drop the older edge constraint:
ALTER TABLE bought DROP CONSTRAINT EC_BOUGHT;
GO
-- If needed, you can rename the new edge constraint to match the original name:
EXECUTE sp_rename '[dbo].[EC_BOUGHT_NEW]', '[dbo].[EC_BOUGHT]';
先添加新的“超集”约束,同时不删除之前的约束,这样可使操作变为仅元数据的操作 – 即无需检查 bought
表中的所有现有数据,因为其包含现有约束。
这样,为了能够在 bought
边缘中使用给定的边缘,其必须满足 EC_BOUGHT_NEW
约束中的边缘约束子句之一。 因此,可允许任何尝试将有效的 Customer
连接到 Product
或将 Supplier
连接到 Product
的节点。
删除边缘约束
下面的示例先标识边缘约束名称,再删除边缘约束。
-- CREATE node and edge tables
CREATE TABLE Customer
(
ID INTEGER PRIMARY KEY
, CustomerName VARCHAR(100)
)
AS NODE;
GO
CREATE TABLE Product
(
ID INTEGER PRIMARY KEY
, ProductName VARCHAR(100)
) AS NODE;
GO
CREATE TABLE bought
(
PurchaseCount INT
, CONSTRAINT EC_BOUGHT CONNECTION (Customer TO Product)
)
AS EDGE;
GO
-- Return the name of edge constraint.
SELECT name
FROM sys.edge_constraints
WHERE type = 'EC' AND parent_object_id = OBJECT_ID('bought');
GO
-- Delete the primary key constraint.
ALTER TABLE bought
DROP CONSTRAINT EC_BOUGHT;
修改边缘约束
要使用 Transact-SQL 修改边缘约束,必须首先删除现有的边缘约束,然后用新定义重新创建。
查看边缘约束
目录视图中仅显示用户拥有的安全对象的元数据,或用户对其拥有某些权限的安全对象的元数据。 有关详细信息,请参阅 Metadata Visibility Configuration。
此实例返回 tempdb
数据库中边缘表 bought
的所有边缘约束及其属性。
-- CREATE node and edge tables
CREATE TABLE Customer
(
ID INTEGER PRIMARY KEY
, CustomerName VARCHAR(100)
)
AS NODE;
GO
CREATE TABLE Supplier
(
ID INTEGER PRIMARY KEY
, SupplierName VARCHAR(100)
)
AS NODE;
GO
CREATE TABLE Product
(
ID INTEGER PRIMARY KEY
, ProductName VARCHAR(100)
)
AS NODE;
-- CREATE edge table with edge constraints.
CREATE TABLE bought
(
PurchaseCount INT
, CONSTRAINT EC_BOUGHT CONNECTION (Customer TO Product, Supplier TO Product)
)
AS EDGE;
-- Query sys.edge_constraints and sys.edge_constraint_clauses to view
-- edge constraint properties.
SELECT
EC.name AS edge_constraint_name
, OBJECT_NAME(EC.parent_object_id) AS edge_table_name
, OBJECT_NAME(ECC.from_object_id) AS from_node_table_name
, OBJECT_NAME(ECC.to_object_id) AS to_node_table_name
, is_disabled
, is_not_trusted
FROM sys.edge_constraints EC
INNER JOIN sys.edge_constraint_clauses ECC
ON EC.object_id = ECC.object_id
WHERE EC.parent_object_id = object_id('bought');