Navegar por relações com consultas de gráfico
Algumas relações de dados são naturalmente representadas como redes, incluindo conexões sociais, hierarquias organizacionais, recomendações de produtos e padrões de detecção de fraudes. Embora você possa modelar essas relações usando chaves e junções estrangeiras, as consultas de grafo usando o MATCH operador fornecem uma maneira mais intuitiva e geralmente mais eficiente de percorrer dados conectados.
Visualizar estruturas de dados do grafo
Antes de escrever consultas de grafo, ele ajuda a visualizar como os dados do grafo são organizados. Considere uma rede social simples em que as pessoas se conheçam e comprem produtos:
Neste modelo:
- Nodos (caixas) representam entidades como pessoas e produtos
- Bordas (setas) representam relações entre nós. Direção de seta indica a direção da relação (Alice conhece Bob, não necessariamente Bob conhece Alice).
Observação
Este diagrama ilustra os conceitos do grafo. Os exemplos de código em toda essa unidade usam dados semelhantes, mas simplificados, para se concentrar em recursos específicos.
Entender os recursos do grafo
Os recursos de gráfico estendem o modelo relacional com tabelas dedicadas a nós e bordas. Os nós representam entidades como pessoas, produtos e locais. As bordas representam relações entre elas, como "knows", "purchased" ou "located in".
A principal vantagem das consultas de grafo é a correspondência de padrões. Em vez de escrever junções múltiplas complexas, você expressa o padrão que está procurando usando uma sintaxe de estilo ASCII:
-- Traditional relational approach (multiple joins)
SELECT p1.Name, p2.Name
FROM Person AS p1
INNER JOIN Friendship AS f ON p1.PersonID = f.Person1ID
INNER JOIN Person AS p2 ON f.Person2ID = p2.PersonID;
-- Graph approach (pattern matching)
SELECT Person1.Name, Person2.Name
FROM Person AS Person1, Friendship, Person AS Person2
WHERE MATCH(Person1-(Friendship)->Person2);
Observação
As tabelas de grafo são totalmente compatíveis com os recursos relacionais existentes. Você pode unir tabelas de grafo com tabelas regulares, usar índices e aplicar todas as operações T-SQL padrão.
Criar tabelas de nós
As tabelas de nós armazenam entidades em seu grafo. Crie-os usando CREATE TABLE com a cláusula AS NODE.
-- Create a Person node table
CREATE TABLE dbo.Person (
PersonID INT PRIMARY KEY,
Name NVARCHAR(100) NOT NULL,
Email NVARCHAR(200),
Department NVARCHAR(50)
) AS NODE;
-- Create a Product node table
CREATE TABLE dbo.Product (
ProductID INT PRIMARY KEY,
Name NVARCHAR(200) NOT NULL,
Category NVARCHAR(100),
Price DECIMAL(10, 2)
) AS NODE;
-- Create a Location node table
CREATE TABLE dbo.Location (
LocationID INT PRIMARY KEY,
City NVARCHAR(100) NOT NULL,
CountryRegion NVARCHAR(100) NOT NULL
) AS NODE;
O SQL Server adiciona automaticamente uma coluna $node_id às tabelas de nós que identifica exclusivamente cada nó. O sistema usa essa coluna internamente para relações de grafo.
O exemplo a seguir insere quatro pessoas na tabela de nó Pessoa e, em seguida, consulta a tabela para mostrar as colunas de negócios e as colunas geradas pelo sistema $node_id. Observe que a instrução INSERT usa apenas as colunas definidas pelo usuário. O SQL Server gera automaticamente $node_id para cada linha:
-- Insert person data using standard INSERT syntax
INSERT INTO dbo.Person (PersonID, Name, Email, Department)
VALUES
(1, 'Alice Johnson', 'alice@contoso.com', 'Engineering'),
(2, 'Bob Smith', 'bob@contoso.com', 'Marketing'),
(3, 'Carol Davis', 'carol@contoso.com', 'Engineering'),
(4, 'David Lee', 'david@contoso.com', 'Sales');
-- Query shows the system-generated $node_id alongside user columns
SELECT $node_id, PersonID, Name FROM dbo.Person;
Criar tabelas de borda
As tabelas de borda representam relações entre nós. Crie-os usando CREATE TABLE com a cláusula AS EDGE.
-- Create a "reports to" relationship edge
CREATE TABLE dbo.ReportsTo (
StartDate DATE,
ReportType NVARCHAR(50)
) AS EDGE;
-- Create a "purchased" relationship edge
CREATE TABLE dbo.Purchased (
PurchaseDate DATE NOT NULL,
Quantity INT NOT NULL,
TotalAmount DECIMAL(10, 2)
) AS EDGE;
-- Create a "knows" relationship edge (social connection)
CREATE TABLE dbo.Knows (
ConnectionDate DATE,
ConnectionStrength INT -- 1-10 scale
) AS EDGE;
O SQL Server adiciona $edge_id, $from_id e $to_id colunas automaticamente às tabelas de borda. Você pode inserir arestas especificando os valores $from_id e $to_id dos nós conectados, como este:
-- Alice reports to Bob
INSERT INTO dbo.ReportsTo ($from_id, $to_id, StartDate, ReportType)
SELECT
(SELECT $node_id FROM dbo.Person WHERE Name = 'Alice Johnson'),
(SELECT $node_id FROM dbo.Person WHERE Name = 'Bob Smith'),
'2023-01-15',
'Direct';
-- Create social connections
INSERT INTO dbo.Knows ($from_id, $to_id, ConnectionDate, ConnectionStrength)
SELECT
(SELECT $node_id FROM dbo.Person WHERE Name = 'Alice Johnson'),
(SELECT $node_id FROM dbo.Person WHERE Name = 'Carol Davis'),
'2022-06-01',
8;
Dica
As tabelas de borda podem armazenar propriedades sobre a relação em si, como datas, pesos ou tipos. Isso é útil para análise temporal ou algoritmos de grafo ponderados.
Consultar grafos com a cláusula MATCH
A MATCH cláusula usa uma sintaxe de padrão para especificar as relações que você deseja encontrar. O padrão básico usa setas para mostrar a direção da relação:
-- Find who reports to whom
SELECT
Employee.Name AS Employee,
Manager.Name AS Manager,
r.StartDate
FROM dbo.Person AS Employee,
dbo.ReportsTo AS r,
dbo.Person AS Manager
WHERE MATCH(Employee-(r)->Manager);
A direção da seta importa:
-
(Node1)-(Edge)->(Node2): a borda vai de Node1 a Node2 -
(Node1)<-(Edge)-(Node2): a borda vai de Node2 a Node1
O exemplo a seguir localiza todas as pessoas que conhecem Alice:
SELECT
Connector.Name AS PersonWhoKnowsAlice,
k.ConnectionStrength
FROM dbo.Person AS Connector,
dbo.Knows AS k,
dbo.Person AS Target
WHERE MATCH(Connector-(k)->Target)
AND Target.Name = 'Alice Johnson';
Percorrer várias relações
Consultas de salto único encontram conexões diretas, mas os bancos de dados gráficos se destacam em percursos de vários saltos. Você pode encadear vários padrões de borda em uma única cláusula MATCH para seguir caminhos por meio de várias relações. Essa funcionalidade permite que você responda perguntas como "quem são os amigos dos meus amigos?" ou "quais produtos foram comprados pelos meus colegas?" sem escrever subconsultas aninhadas complexas.
O exemplo a seguir encontra amigos de amigos encadeando dois relacionamentos KNOWS. O padrão Person1-(k1)->Person2-(k2)->Person3 começa em Pessoa1, segue uma aresta CONHECE para Pessoa2, e, em seguida, segue outra aresta CONHECE para chegar à Pessoa3.
-- Find friends of friends (2-hop connections)
SELECT DISTINCT
Person1.Name AS Person,
Person3.Name AS FriendOfFriend
FROM dbo.Person AS Person1,
dbo.Knows AS k1,
dbo.Person AS Person2,
dbo.Knows AS k2,
dbo.Person AS Person3
WHERE MATCH(Person1-(k1)->Person2-(k2)->Person3)
AND Person1.Name = 'Alice Johnson'
AND Person3.Name <> Person1.Name; -- Exclude self
Você também pode combinar diferentes tipos de relação em uma única passagem. O exemplo a seguir cruza de bordas KNOWS a PURCHASED para encontrar quais produtos foram comprados por pessoas que uma determinada pessoa conhece:
-- Find products purchased by people in the same department
SELECT DISTINCT
p1.Name AS Person,
p1.Department,
prod.Name AS Product
FROM dbo.Person AS p1,
dbo.Knows AS k,
dbo.Person AS p2,
dbo.Purchased AS pu,
dbo.Product AS prod
WHERE MATCH(p1-(k)->p2-(pu)->prod)
AND p1.Department = p2.Department;
Importante
Cada alias de Edge Table só pode aparecer uma vez em um único padrão MATCH. Para percorrer o mesmo tipo de borda várias vezes, use aliases separados.
Usar SHORTEST_PATH para travessias de comprimento variável
Você pode usar SHORTEST_PATH para localizar a conexão mais curta em um número variável de relações. A palavra-chave FOR PATH marca tabelas que participam da correspondência de comprimento variável e quantificadores como + (um ou mais) ou {1,3} (um a três) controlam a profundidade da passagem.
O exemplo a seguir localiza todas as pessoas acessíveis de Alice dentro de três saltos e contabiliza a distância para cada pessoa:
SELECT
StartPerson.Name,
LAST_VALUE(ReachablePerson.Name) WITHIN GROUP (GRAPH PATH) AS ReachablePerson,
COUNT(ReachablePerson.Name) WITHIN GROUP (GRAPH PATH) AS Distance
FROM dbo.Person AS StartPerson,
dbo.Knows FOR PATH AS k,
dbo.Person FOR PATH AS ReachablePerson
WHERE MATCH(SHORTEST_PATH(StartPerson(-(k)->ReachablePerson){1,3}))
AND StartPerson.Name = 'Alice Johnson';
Escolher entre abordagens relacionais e de grafo
Consultas em grafos nem sempre são a melhor opção. Considere estas diretrizes ao decidir entre o grafo e as abordagens relacionais tradicionais:
Use consultas de grafo quando:
- Relações são o foco principal de suas consultas
- Você precisa explorar profundidades variáveis ou desconhecidas (amigos de amigos de amigos)
- Os dados naturalmente formam uma rede (grafos sociais, hierarquias, rotas)
- Os padrões de consulta exigiriam muitas autojunções no SQL relacional
- Você está executando a análise de localização de caminhos ou conectividade
Use consultas relacionais quando:
- As relações são simples e de profundidade fixa (pai-filho com um nível)
- Você está principalmente filtrando e agregando atributos de entidade
- O modelo de dados é principalmente tabular com poucas relações
- O desempenho é essencial, e os índices em chaves estrangeiras são suficientes
- Sua equipe está mais familiarizada com os padrões sql tradicionais
Solução de desafios comuns em consultas de grafos
As consultas do Graph têm requisitos de sintaxe exclusivos que podem causar erros. A tabela a seguir descreve os desafios comuns e como resolvê-los.
| Desafio | Motivo | Solução |
|---|---|---|
| A consulta não retorna resultados | A direção da seta no MATCH padrão não corresponde à forma como as bordas foram inseridas |
Verifique como as bordas foram inseridas. Se $from_id for Funcionário e $to_id for Gerente, a seta deverá apontar de Funcionário para Gerente. |
| Erro de sintaxe com borda repetida | Mesmo alias de borda usado várias vezes em um padrão MATCH |
Crie aliases separados para cada passagem do mesmo tipo de borda. |
SHORTEST_PATH falha na consulta |
Tabelas de aresta e vértice não marcadas com FOR PATH |
Adicione a palavra-chave FOR PATH a todas as tabelas que participam da correspondência de tamanho variável. |
| As bordas fazem referência a nós inexistentes | Colunas de chave do negócio utilizadas em vez de valores de $node_id |
Use subconsultas para selecionar $node_id em tabelas de nós ao inserir bordas. |
Observação
As tabelas do Graph e o MATCH operador estão disponíveis no SQL Server 2017 e posterior e no Banco de Dados SQL do Azure. A SHORTEST_PATH função requer o SQL Server 2019 ou posterior. Verifique a documentação da sua plataforma para a disponibilidade de funcionalidades específicas.
Para obter mais informações sobre os recursos do grafo, consulte o processamento do Graph com o SQL Server e MATCH (Transact-SQL).