T-SQL を使用してグラフ データベースを作成し、いくつかのパターン マッチング クエリを実行する
適用対象: SQL Server 2017 (14.x) 以降 Azure SQL DatabaseAzure SQL Managed Instance
このサンプルでは、ノードとエッジを含むグラフ データベースを作成し、新しい MATCH 句を使用して一部のパターンを照合し、グラフを走査する Transact-SQL スクリプトを提供します。 このサンプル スクリプトは、Azure SQL Database と SQL Server 2017 (14.x) 以降のバージョンの両方で動作します。
サンプル スキーマ
このサンプルでは、ノード、および ノードを持つPeople
Restaurant
架空のソーシャル ネットワークのグラフ スキーマをCity
作成します。 これらのノードは、、Likes
LivesIn
、および LocatedIn
エッジを使用してFriends
相互に接続されます。 次の図は、、person
、ノード、エッジを含むrestaurant
サンプル スキーマを LocatedIn
Likes
LivesIn
示しています。 city
サンプル スクリプト
次のサンプル スクリプトでは、新しい T-SQL 構文を使用してノード テーブルとエッジ テーブルを作成します。 ステートメントを使用してノード テーブルとエッジ テーブルにデータを INSERT
挿入する方法と、パターン マッチングとナビゲーションに 句を使用 MATCH
する方法についても説明します。
このスクリプトでは、次の手順を実行します。
- という名前
GraphDemo
のデータベースを作成します。 - ノード テーブルを作成します。
- エッジ テーブルを作成します。
-- 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;
次に、リレーションシップを表すデータを挿入します。
- ノード テーブルにデータを挿入します。
- ノード テーブルへの挿入は、通常のテーブルへの挿入と同じです。
- エッジ テーブルにデータを挿入します。この場合は、各ユーザーがエッジに好きなレストランを
likes
配置します。- エッジ テーブルに挿入するときに、from
$from_id
列と$to_id
列を$node_id
指定します。
- エッジ テーブルに挿入するときに、from
- エッジにデータを
livesIn
挿入して、ユーザーを住んでいる都市に関連付けます。 - エッジにデータを
locatedIn
挿入して、レストランを所在地の都市に関連付けます。 - 関連付けられている友人に
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));
次に、データに対してクエリを実行して、データから分析情報を見つけます。
- Graph MATCH 関数を使用して、John が気に入っているレストランを見つけます。
- ジョンの友人が好きなレストランを見つけます。
- 住んでいるのと同じ都市のレストランが好きな人を見つけます。
-- 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