适用于:Microsoft
Fabric 预览版中的 SQL Server 2019 (15.x) 及更高版本
Azure SQL 数据库
Azure SQL 托管实例 SQL 数据库
边缘约束可用于对 SQL Server 图形数据库中的边缘表强制执行数据完整性和特定语义。
Edge Constraints
默认情况下,边缘表不会为边缘的端点强制执行任何操作。 也就是说,无论何种类型,图形数据库中的边缘都可以将任何节点连接到任何其他节点。
SQL Graph 支持边缘约束,使用户能够向其边缘表添加约束,从而强制执行特定语义,同时保持数据完整性。 将新的边缘添加到具有边缘约束的边缘表时,数据库引擎强制让边缘尝试连接的节点存在于正确的节点表中。 如果有任何边缘引用该节点,则还确保了不会删除该节点。
边缘约束子句
单个边缘约束都由一个或多个边缘约束子句组成。
CONSTRAINT constraint_name CONNECTION (cause1[, clause2...])
- 边缘约束子句是一对节点表名称,由
TO
关键字分隔。 - 边缘约束子句中的第一个表名是边缘关系的 FROM 节点表的名称。
- 边缘约束子句中的第二个表名是边缘关系的 TO 节点表的名称。
- 因此,表名称对指示边缘关系的方向。
- 如前文所述,边缘约束可以包含一个或多个边缘约束子句。
多个约束和子句
- 为同一个边缘表定义的多个边缘约束与
AND
运算符一起使用。 - 在同一个边缘约束中定义的多个边缘约束子句与 运算符一起使用。
请考虑图形中的 Supplier
和 Customer
节点。 每个节点可通过单个共享边缘表与 Product
节点关联:bought
。
bought
边缘表支持 Customer-(bought)->Product
和 Supplier-(bought)->Product
关系类型。 可以通过使用具有多个边缘约束子句的单个边缘约束来完成此操作。
Examples
CONSTRAINT EC_BOUGHT CONNECTION (Customer TO Product)
上面的示例显示了一个边缘约束,其中包含一个边缘约束子句。 此约束支持 Customer-(bought)->Product
。 也就是说,将允许插入从 bought
到 Customer
的 Product
边缘关系。 插入任何其他节点组合(如 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
在前面的示例中,假设现在还需要通过 Supplier
边缘表包含 Product
到 bought
的关系。 可以尝试添加新的边缘约束:
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。
此实例返回 bought
数据库中边缘表 tempdb
的所有边缘约束及其属性。
-- 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');