Графовая модель БД "Живопись на марках"

Скрыть

Графовую модель данной предметной области можно представить в виде показанной на рисунке схемы, где прямоугольниками представлены узлы, а стрелками ребра – связи между узлами. Тип связи указан надписью у ребра. Обратите внимание на связь «обучал», которую мы не реализовали в реляционной схеме данных. Это ребро связывает экземпляры одной и той же сущности – художник – отношением «учитель - ученик».

Для реализации этой модели будем использовать SQL Server, который в издании 2017 начал поддерживать графовую модель данных. В данной реализации узлы и связи представляются таблицами специального типа. Давайте создадим их в схеме Graph (о структуре этих таблиц можно почитать здесь).

Скрипт схемы графовой БД (SQL Server)

Показать

/* Схема Graph */
CREATE SCHEMA Graph;

/* Музеи */
CREATE TABLE Graph.Museums(
id INT PRIMARY KEY,
name VARCHAR(255),
town VARCHAR(255) 
) AS NODE;

/* Художники */
CREATE TABLE Graph.Artists(
id INT PRIMARY KEY,
name VARCHAR(255),
birth INT,
death INT,
country VARCHAR(255) 
) AS NODE;

/* Картины */
CREATE TABLE Graph.Paints(
id INT PRIMARY KEY,
name VARCHAR(255),
creation VARCHAR(255) 
) AS NODE;

/* Связь "Имеет" */
CREATE TABLE graph.Has AS EDGE;

/* Связь "Нарисовал" */
CREATE TABLE graph.Draws AS EDGE;

/* Связь "Обучал" */
CREATE TABLE graph.Teaches AS EDGE;

Следует обратить внимание, что таблицы ребер в данном случае вообще не имеют определяемых пользователем столбцов, хотя ничто не мешает вам при необходимости их создать.

Теперь нам нужны данные. Возьмем их из реляционной базы данных, которая уже обсуждалась ранее. (Здесь мы предполагаем, что реляционная структура реализована в той же самой базе данных SQL Server в схеме dbo).

/* Узлы */
INSERT INTO Graph.Museums(id, name, town)
SELECT id, name, town FROM dbo.Museums;

INSERT INTO Graph.Artists
SELECT a.id, a.name, birth, death, c.name country FROM dbo.Artists  a 
JOIN dbo.Countries c ON c.id=a.country_id; 

INSERT INTO Graph.Paints(id,name,creation)
SELECT id,name, creation FROM dbo.Paints;

/* Связи */
INSERT INTO Graph.Has($from_id, $to_id)
SELECT gm.$node_id, gp.$node_id FROM Graph.Museums gm 
JOIN dbo.Paints p ON gm.id = p.museum_id 
JOIN Graph.Paints gp ON gp.id =p.id;

INSERT INTO Graph.Draws($from_id, $to_id)
SELECT am.$node_id, gp.$node_id FROM Graph.Artists am 
JOIN dbo.Paints p ON am.id = p.artist_id 
JOIN Graph.Paints gp ON gp.id =p.id;

Для третьей таблицы (Teaches), которая реализует связь «учитель – ученик», у нас нет данных в реляционной модели. Поэтому эти данные будем вносить вручную. Здесь мы приводим пару строк в качестве примера:

INSERT INTO Graph.Teaches($from_id, $to_id) VALUES
((SELECT $node_id FROM Graph.Artists WHERE id=212), (SELECT $node_id FROM Graph.Artists WHERE id=241)),
((SELECT $node_id FROM Graph.Artists WHERE id=88), (SELECT $node_id FROM Graph.Artists WHERE id=39));

Эти строки устанавливают связь между Рубо Ф.А. (учитель, id=212) и АВИЛОВЫМ М.И. (ученик, id=241), а также ПОЛЕНОВЫМ В.Д. (учитель, id=88) и АРХИПОВЫМ А.Е. (ученик, id=39).

Заметим, что поскольку граф в реализации SQL Server представляется таблицами, мы можем для извлечения данных из графовой базы использовать обычный синтаксис SQL-запросов. Однако для демонстрации новых возможностей я хочу использовать специальные средства, а именно, функцию MATCH, позволяющую создавать шаблоны для поиска узлов в стиле языка Cypher.

Примеры запросов к БД

1. Все пары учитель-ученик можно получить с помощью следующего запроса:

select teacher.name учитель ,pupil.name ученик
from graph.Teaches t, graph.Artists teacher, graph.artists Pupil
where match(teacher-(t)->pupil);

2. Найти учителя художника Кончаловского П.П. .

select teacher.name учитель
from graph.Teaches t, graph.Artists teacher, graph.artists Pupil
where match(teacher-(t)->pupil) and pupil.name like '%Кончаловский%';
учитель
САВИНСКИЙ В.Е.

Предикат LIKE в предложении WHERE используется для того, чтобы выполнять поиск только по фамилии без учета инициалов.

3. Найти учеников художника Перова В.Г.

select pupil.name ученик
from graph.Teaches t,graph.Artists teacher,graph.artists Pupil
where match(teacher-(t)->pupil) and teacher.name like '%Перов%';
ученик
КАСАТКИН Н.А.
ЛЕБЕДЕВ К.В.
НЕСТЕРОВ М.В.
РЯБУШКИН А.П.

4. Найти учителя художника Нестерова.

select teacher0.name "учитель учителя", teacher.name учитель ,pupil.name ученик
from graph.Teaches t, graph.Teaches t0 ,graph.Artists teacher,graph.artists Pupil, graph.Artists teacher0
where match(teacher0-(t0)->teacher-(t)->pupil) and teacher.name like '%Нестеров%';
учитель учителяучительученик
ПЕРОВ В.Г.НЕСТЕРОВ М.В.БОГАТКИН В.В.

5. Картины художника Шишкина, которые находятся в Русском музее.

select paint.name картина ,museum.name музей
from graph.Paints paint,graph.Artists artist,graph.museums museum,
	 graph.Has h, graph.draws d
where match(museum-(h)->paint<-(d)-artist)
	and artist.name like '%Шишкин%' and museum.name like 'Русский%';
картинамузей
ДубыРусский Музей (Мих.дв.)
Корабельная рощаРусский Музей (Мих.дв.)