邊緣條件約束

適用於:SQL Server 2019 (15.x) 和更新版本 Azure SQL 資料庫Azure SQL 受控執行個體

邊緣條件約束可以用來強制執行資料完整性,以及 SQL Server 圖形資料庫邊緣資料表中的特定語意。

邊緣條件約束

根據預設,邊緣資料表不會針對邊緣的端點強制執行任何作業。 亦即,圖形資料庫中的邊緣可以將任何節點連線至任何其他節點,不論類型為何。

SQL Graph 支援邊緣條件約束,讓使用者將條件約束新增至其邊緣資料表,藉此強制執行特定語意同時維護資料完整性。 使用邊緣條件約束將新的邊緣新增至邊緣資料表時,資料庫引擎 會強制邊緣所嘗試連線的節點存在於正確的節點資料表。 如果參考節點的任何邊緣,也可確保該節點無法卸除。

邊緣條件約束子句

單一邊緣條件約束都是由一或多個邊緣條件約束子句所組成。

CONSTRAINT constraint_name CONNECTION (cause1[, clause2...])
  • 邊緣條件約束子句是一對節點資料表名稱,以 TO 關鍵字分隔。
  • 邊緣條件約束子句中的第一個資料表名稱是邊緣關聯性的 FROM 節點資料表名稱。
  • 邊緣條件約束子句中的第二個資料表名稱是邊緣關聯性的 TO 節點資料表名稱。
  • 因此,資料表名稱配對會指出邊緣關聯性的「方向」。
  • 如先前所述,邊緣條件約束可以包含一或多個邊緣條件約束子句。

多個條件約束和子句

  • 針對相同邊緣資料表定義的多個邊緣條件約束,會使用 AND 運算子強制執行。
  • 相同邊緣資料表內定義的多個邊緣條件約束「子句」,會使用 OR 運算子強制執行。

請考慮圖形中的 SupplierCustomer 節點。 每個都可以透過單一共用邊緣資料表與 Product 節點相關:boughtbought 邊緣資料表支援 Customer-(bought)->ProductSupplier-(bought)->Product 關聯性類型。 這可以使用單一邊緣條件約束搭配多個邊緣條件約束子句來完成。

範例
CONSTRAINT EC_BOUGHT CONNECTION (Customer TO Product)

上述範例顯示一個邊緣條件約束,搭配一個邊緣條件約束子句。 此條件約束支援 Customer-(bought)->Product。 也就是說,將允許插入 boughtCustomerProduct 的邊緣關聯性。 如果您嘗試插入任何其他節點組合,例如 Supplier-(bought)->Product,則即使它可能描述真實世界中的有效關聯性,還是會失敗。

CONSTRAINT EC_BOUGHT CONNECTION (Supplier TO Product, Customer TO Product)

上述範例定義一個邊緣條件約束,搭配兩個邊緣條件約束子句。 這些條件約束子句允許 bought 邊緣包含 Supplier-(bought)->ProductCustomer-(bought)->Product 關聯性。 將任何其他類型的邊緣關聯性插入至 bought 資料表將會失敗。

CONSTRAINT EC_BOUGHT1 CONNECTION (Supplier TO Product)
CONSTRAINT EC_BOUGHT2 CONNECTION (Customer TO Product)

上述範例顯示相同邊緣資料表上的兩個條件約束,每個邊緣條件約束都指定一個條件約束子句。 在此情況下,SQL 只會允許同時滿足 BOTH 邊緣條件約束子句的插入。 這是不可能的。 沒有任何節點組可以同時滿足這兩個邊緣條件約束子句。 此邊緣條件約束組合會使邊緣資料表無法使用。

如需可在實際案例中使用多個邊緣條件約束的詳細說明,請參閱本頁稍後的「使用新的邊緣條件約束子句,在現有的邊緣資料表上建立新的邊緣條件約束」範例。

邊緣條件約束的索引

建立邊緣條件約束並不會自動在邊緣資料表的 $from_id$to_id 資料行上建立對應的索引。 如果您有點查閱查詢或 OLTP 工作負載,則建議在 $from_id$to_id 配對上手動建立索引。

邊緣條件約束的 ON DELETE 參考動作

邊緣條件約束串聯式動作可讓使用者定義當使用者刪除指定邊緣所連接的節點時,資料庫引擎將採取的動作。 您可以定義下列參考動作: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 邊緣資料表上建立邊緣條件約束,並定義 ON DELETE CASCADE 參考動作。

-- 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 邊緣資料表包含 SupplierProduct 的關聯性。 您可以嘗試新增邊緣條件約束:

ALTER TABLE bought ADD CONSTRAINT EC_BOUGHT1 CONNECTION (Supplier TO Product);

不過,新增邊緣條件約束不是正確的解決方案。 我們已在 bought 邊緣資料表上建立兩個不同的邊緣條件約束:EC_BOUGHTEC_BOUGHT1。 這兩個邊緣條件約束會有不同的邊緣條件約束子句。 如果邊緣資料表上有一個以上的邊緣條件約束,則指定的邊緣必須滿足邊緣資料表中允許的 ALL 邊緣條件約束。 由於這裡沒有任何邊緣能夠滿足 EC_BOUGHTEC_BOUGHT1,因此只要 bought 邊緣資料表中有任何資料列,上述 ALTER TABLE 陳述式將會失敗。

若要成功建立此邊緣條件約束,指定的方法是遵循序列,如下列範例所示:

-- 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');

下一步