エッジ制約
適用対象: SQL Server 2019 (15.x) 以降
Azure SQL Database
Azure SQL Managed Instance
エッジ制約を使用して、データ整合性と特定のセマンティクスを SQL Server グラフ データベース内のエッジ テーブルに適用できます。
エッジ制約
既定では、エッジ テーブルでエッジのエンドポイントに対して強制できることは何もありません。 つまり、グラフ データベース内のエッジは、その種類に関係なく、任意のノードを他の任意のノードに接続することができました。
SQL Graph ではエッジ制約がサポートされています。これにより、ユーザーは、各自のエッジ テーブルに制約を追加することで特定のセマンティクスを適用でき、データの整合性も管理できます。 エッジ制約を持つエッジ テーブルに新しいエッジが追加される場合、データベース エンジンでは、エッジが接続を試みるノードが適切なノード テーブルに存在している必要があります。 また、ノードがエッジによって参照されている場合は、ノードを削除することはできません。
エッジ制約句
1 つのエッジ制約は、1 つまたは複数のエッジ制約句で構成されます。
CONSTRAINT constraint_name CONNECTION (cause1[, clause2...])
- エッジ制約句とは、
TO
キーワードで区切られた、ノード テーブル名のペアのことです。 - エッジ制約句の 1 つ目のテーブル名は、エッジ リレーションシップの FROM ノード テーブルの名前です。
- エッジ制約句の 2 つ目のテーブル名は、エッジ リレーションシップの TO ノード テーブルの名前です。
- したがって、テーブル名のペアは、エッジ リレーションシップの方向を示します。
- 前に説明したように、エッジ制約には 1 つ以上のエッジ制約句を含めることができます。
複数の制約と句
- 同じエッジ テーブルに対して定義された複数のエッジ制約は、
AND
演算子によって適用されます。 - 同じエッジ制約内で定義された複数のエッジ制約句は、
OR
演算子によって適用されます。
グラフ内の Supplier
ノードと Customer
ノードについて考えてみましょう。 各ノードは、1 つの共有エッジ テーブル (bought
) によって Product
ノードに関連付けることができます。 bought
エッジ テーブルでは、Customer-(bought)->Product
および Supplier-(bought)->Product
のリレーションシップの種類がサポートされます。 これは、複数のエッジ制約句を含んだ 1 つのエッジ制約を使用して実現できます。
例
CONSTRAINT EC_BOUGHT CONNECTION (Customer TO Product)
上の例は、1 つのエッジ制約句を含んだ 1 つのエッジ制約を示したものです。 この制約では、Customer-(bought)->Product
がサポートされます。 つまり、Customer
から Product
への bought
エッジ リレーションシップを挿入することが許可されます。 ノードのその他の組み合わせ (Supplier-(bought)->Product
など) を挿入しようとすると、現実世界で有効なリレーションシップが記述されていたとしても、操作は失敗します。
CONSTRAINT EC_BOUGHT CONNECTION (Supplier TO Product, Customer TO Product)
上の例は、2 つのエッジ制約句を含んだ 1 つのエッジ制約を定義したものです。 これらの制約句を使用すると、bought
エッジに Supplier-(bought)->Product
または Customer-(bought)->Product
リレーションシップを含めることができます。 他の種類のエッジ リレーションシップを bought
テーブルに挿入しようとすると、操作が失敗します。
CONSTRAINT EC_BOUGHT1 CONNECTION (Supplier TO Product)
CONSTRAINT EC_BOUGHT2 CONNECTION (Customer TO Product)
上の例は、同じエッジ テーブルに対する 2 つの制約を示したものです。各エッジ制約では、1 つの制約句が指定されています。 この場合、SQL では両方のエッジ制約句を同時に満たす挿入のみが許可されます。 これはできません。 両方のエッジ制約句を満たすノード ペアはありません。 このエッジ制約の組み合わせを使用すると、エッジ テーブルは使用できなくなります。
現実世界のシナリオでどのような場合に複数のエッジ制約を使用できるかについて詳しくは、このページで後述される例「既存のエッジ テーブルに、新しいエッジ制約句を含む新しいエッジ制約を作成する」をご覧ください。
エッジ制約のインデックス
エッジ制約を作成しても、エッジ テーブルの $from_id
列と $to_id
列の対応するインデックスは自動的に作成されることはありません。 ポイント ルックアップ クエリまたは OLTP ワークロードがある場合は、$from_id
と $to_id
のペアに対するインデックスを手動で作成することをお勧めします。
エッジ制約に対する削除時の参照操作
エッジ制約に対する連鎖操作では、そのエッジが接続されているノードをユーザーが削除したときに、データベース エンジンが実行するアクションをユーザーが定義できます。 次の参照操作を定義できます: NO ACTION 接続されているエッジがあるノードを削除しようとすると、データベース エンジンによってエラーが生成されます。
CASCADE データベースからノードを削除すると、接続されているエッジが削除されます。
エッジ制約の使用
SQL Server では、Transact-SQL を使用してエッジ制約を作成できます。 エッジ制約は、グラフ エッジ テーブルにのみ定義できます。 エッジ制約を作成、削除、または変更するには、テーブルに対する 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
制約に 2 つのエッジ制約句があります。Customer
を Product
に接続するものと、Supplier
を Product
に接続するものです。 両方の句は、論理和演算で適用されます。 つまり、指定されたエッジがエッジ テーブルで許可されるには、これら 2 つの句のいずれかを満たす必要があります。
既存のエッジ テーブルに、新しいエッジ制約句を含む新しいエッジ制約を作成する
次の例では、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
エッジ テーブルに 2 つの別個のエッジ制約 (EC_BOUGHT
と EC_BOUGHT1
) を作成しました。 これらのエッジ制約には、どちらにも、異なるエッジ制約句があります。 エッジ テーブルに複数のエッジ制約がある場合、特定のエッジがエッジ テーブルで許可されるには、すべてのエッジ制約を満たす必要があります。 ここでは EC_BOUGHT
と EC_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」を参照してください。
この例では、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');