T-SQL を使用してグラフ データベースを作成し、いくつかのパターン マッチング クエリを実行する

適用対象: SQL Server 2017 (14.x) 以降 Azure SQL DatabaseAzure SQL Managed Instance

このサンプルでは、ノードとエッジを含むグラフ データベースを作成し、新しい MATCH 句を使用して一部のパターンを照合し、グラフを走査する Transact-SQL スクリプトを提供します。 このサンプル スクリプトは、Azure SQL Database と SQL Server 2017 (14.x) 以降のバージョンの両方で動作します。

サンプル スキーマ

このサンプルでは、ノード、および ノードを持つPeopleRestaurant架空のソーシャル ネットワークのグラフ スキーマをCity作成します。 これらのノードは、、LikesLivesIn、および LocatedIn エッジを使用してFriends相互に接続されます。 次の図は、、person、ノード、エッジを含むrestaurantサンプル スキーマを LocatedInLikesLivesIn示しています。 city

レストラン、市区町村、人物ノード、LivesIn、LocatedIn、Likes エッジを含むサンプル スキーマを示す図。

サンプル スクリプト

次のサンプル スクリプトでは、新しい T-SQL 構文を使用してノード テーブルとエッジ テーブルを作成します。 ステートメントを使用してノード テーブルとエッジ テーブルにデータを INSERT 挿入する方法と、パターン マッチングとナビゲーションに 句を使用 MATCH する方法についても説明します。

このスクリプトでは、次の手順を実行します。

  1. という名前 GraphDemoのデータベースを作成します。
  2. ノード テーブルを作成します。
  3. エッジ テーブルを作成します。
-- Create a GraphDemo database
IF NOT EXISTS (SELECT * FROM sys.databases WHERE NAME = 'graphdemo')
    CREATE DATABASE GraphDemo;
GO

USE GraphDemo;
GO

-- Create NODE tables
CREATE TABLE Person (
  ID INTEGER PRIMARY KEY,
  name VARCHAR(100)
) AS NODE;

CREATE TABLE Restaurant (
  ID INTEGER NOT NULL,
  name VARCHAR(100),
  city VARCHAR(100)
) AS NODE;

CREATE TABLE City (
  ID INTEGER PRIMARY KEY,
  name VARCHAR(100),
  stateName VARCHAR(100)
) AS NODE;

-- Create EDGE tables.
CREATE TABLE likes (rating INTEGER) AS EDGE;
CREATE TABLE friendOf AS EDGE;
CREATE TABLE livesIn AS EDGE;
CREATE TABLE locatedIn AS EDGE;

次に、リレーションシップを表すデータを挿入します。

  1. ノード テーブルにデータを挿入します。
    1. ノード テーブルへの挿入は、通常のテーブルへの挿入と同じです。
  2. エッジ テーブルにデータを挿入します。この場合は、各ユーザーがエッジに好きなレストランを likes 配置します。
    1. エッジ テーブルに挿入するときに、from $from_id 列と $to_id 列を$node_id指定します。
  3. エッジにデータを livesIn 挿入して、ユーザーを住んでいる都市に関連付けます。
  4. エッジにデータを locatedIn 挿入して、レストランを所在地の都市に関連付けます。
  5. 関連付けられている友人に friendOf エッジにデータを挿入します。
-- Insert data into node tables. Inserting into a node table is same as inserting into a regular table
INSERT INTO Person (ID, name)
    VALUES (1, 'John')
         , (2, 'Mary')
         , (3, 'Alice')
         , (4, 'Jacob')
         , (5, 'Julie');

INSERT INTO Restaurant (ID, name, city)
    VALUES (1, 'Taco Dell','Bellevue')
         , (2, 'Ginger and Spice','Seattle')
         , (3, 'Noodle Land', 'Redmond');

INSERT INTO City (ID, name, stateName)
    VALUES (1,'Bellevue','WA')
         , (2,'Seattle','WA')
         , (3,'Redmond','WA');

-- Insert into edge table. While inserting into an edge table,
-- you need to provide the $node_id from $from_id and $to_id columns.
/* Insert which restaurants each person likes */
INSERT INTO likes
    VALUES ((SELECT $node_id FROM Person WHERE ID = 1), (SELECT $node_id FROM Restaurant WHERE ID = 1), 9)
         , ((SELECT $node_id FROM Person WHERE ID = 2), (SELECT $node_id FROM Restaurant WHERE ID = 2), 9)
         , ((SELECT $node_id FROM Person WHERE ID = 3), (SELECT $node_id FROM Restaurant WHERE ID = 3), 9)
         , ((SELECT $node_id FROM Person WHERE ID = 4), (SELECT $node_id FROM Restaurant WHERE ID = 3), 9)
         , ((SELECT $node_id FROM Person WHERE ID = 5), (SELECT $node_id FROM Restaurant WHERE ID = 3), 9);

/* Associate in which city live each person*/
INSERT INTO livesIn
    VALUES ((SELECT $node_id FROM Person WHERE ID = 1), (SELECT $node_id FROM City WHERE ID = 1))
         , ((SELECT $node_id FROM Person WHERE ID = 2), (SELECT $node_id FROM City WHERE ID = 2))
         , ((SELECT $node_id FROM Person WHERE ID = 3), (SELECT $node_id FROM City WHERE ID = 3))
         , ((SELECT $node_id FROM Person WHERE ID = 4), (SELECT $node_id FROM City WHERE ID = 3))
         , ((SELECT $node_id FROM Person WHERE ID = 5), (SELECT $node_id FROM City WHERE ID = 1));

/* Insert data where the restaurants are located */
INSERT INTO locatedIn
    VALUES ((SELECT $node_id FROM Restaurant WHERE ID = 1), (SELECT $node_id FROM City WHERE ID =1))
         , ((SELECT $node_id FROM Restaurant WHERE ID = 2), (SELECT $node_id FROM City WHERE ID =2))
         , ((SELECT $node_id FROM Restaurant WHERE ID = 3), (SELECT $node_id FROM City WHERE ID =3));

/* Insert data into the friendOf edge */
INSERT INTO friendOf
    VALUES ((SELECT $NODE_ID FROM Person WHERE ID = 1), (SELECT $NODE_ID FROM Person WHERE ID = 2))
         , ((SELECT $NODE_ID FROM Person WHERE ID = 2), (SELECT $NODE_ID FROM Person WHERE ID = 3))
         , ((SELECT $NODE_ID FROM Person WHERE ID = 3), (SELECT $NODE_ID FROM Person WHERE ID = 1))
         , ((SELECT $NODE_ID FROM Person WHERE ID = 4), (SELECT $NODE_ID FROM Person WHERE ID = 2))
         , ((SELECT $NODE_ID FROM Person WHERE ID = 5), (SELECT $NODE_ID FROM Person WHERE ID = 4));

次に、データに対してクエリを実行して、データから分析情報を見つけます。

  1. Graph MATCH 関数を使用して、John が気に入っているレストランを見つけます。
  2. ジョンの友人が好きなレストランを見つけます。
  3. 住んでいるのと同じ都市のレストランが好きな人を見つけます。
-- Find Restaurants that John likes
SELECT Restaurant.name
FROM Person, likes, Restaurant
WHERE MATCH (Person-(likes)->Restaurant)
AND Person.name = 'John';

-- Find Restaurants that John's friends like
SELECT Restaurant.name
FROM Person person1, Person person2, likes, friendOf, Restaurant
WHERE MATCH(person1-(friendOf)->person2-(likes)->Restaurant)
AND person1.name='John';

-- Find people who like a restaurant in the same city they live in
SELECT Person.name
FROM Person, likes, Restaurant, livesIn, City, locatedIn
WHERE MATCH (Person-(likes)->Restaurant-(locatedIn)->City AND Person-(livesIn)->City);

最後に、より高度なクエリは、友人の友人の友人を見つけます。 このクエリでは、リレーションシップが "ループ バック" するケースは除外されます。 たとえば、Alice は John の友人です。ヨハネはマリヤの友人です。そしてメアリーはアリスの友人です。 これにより、Alice に "ループ" が戻ります。 多くの場合、このようなループに対して明示的にチェックし、結果を除外する必要があります。

-- Find friends-of-friends-of-friends, excluding those cases where the relationship "loops back".
-- For example, Alice is a friend of John; John is a friend of Mary; and Mary in turn is a friend of Alice.
-- This causes a "loop" back to Alice. In many cases, it is necessary to explicitly check for such loops and exclude the results.
SELECT CONCAT(Person.name, '->', Person2.name, '->', Person3.name, '->', Person4.name)
FROM Person, friendOf, Person as Person2, friendOf as friendOffriend, Person as Person3, friendOf as friendOffriendOfFriend, Person as Person4
WHERE MATCH (Person-(friendOf)->Person2-(friendOffriend)->Person3-(friendOffriendOfFriend)->Person4)
AND Person2.name != Person.name
AND Person3.name != Person2.name
AND Person4.name != Person3.name
AND Person.name != Person4.name;

クリーンアップする

SQL Serverでサンプル用に作成されたスキーマとデータベースをクリーンアップします。

USE graphdemo;
go

DROP TABLE IF EXISTS likes;
DROP TABLE IF EXISTS Person;
DROP TABLE IF EXISTS Restaurant;
DROP TABLE IF EXISTS City;
DROP TABLE IF EXISTS friendOf;
DROP TABLE IF EXISTS livesIn;
DROP TABLE IF EXISTS locatedIn;

USE master;
go
DROP DATABASE graphdemo;
go

Azure SQL Database でサンプル用に作成されたスキーマとデータベースをクリーンアップします。

--Connect to the graphdemo database
DROP TABLE IF EXISTS likes;
DROP TABLE IF EXISTS Person;
DROP TABLE IF EXISTS Restaurant;
DROP TABLE IF EXISTS City;
DROP TABLE IF EXISTS friendOf;
DROP TABLE IF EXISTS livesIn;
DROP TABLE IF EXISTS locatedIn;

--Connect to the master database
DROP DATABASE graphdemo;
go

次のステップ