A property graph describes the connections in your data as vertices and edges: customers raise tickets, agents handle tickets, tickets are about products. Oracle AI Database 26ai defines property graphs over existing tables with SQL/PGQ, part of the SQL standard, and a vector can be one of the columns a graph query returns. The pattern finds the connections; the vector ranks them by meaning.
This guide creates a property graph over help desk tables, queries it with GRAPH_TABLE, ranks paths by how similar their ticket is to a new problem, and finds which important customers are affected.
Code for This Guide
The examples are files 07 to 09 in the examples/ch15 folder of the Oracle AI code repository on GitHub, each with its output.
These examples come from AI Applications with Oracle Database 26ai and APEX 26.1, a book of 237 tested examples of AI in Oracle Database and APEX.
They use the customers, agents, products, and tickets of the sample schema from setup/atlas, with the ticket embeddings from how to generate embeddings in SQL with VECTOR_EMBEDDING.
Create a Property Graph
CREATE PROPERTY GRAPH declares which tables are vertices and which are edges, how the edges connect the vertices, and which columns are properties. It copies nothing: the graph is a way of querying the tables.
Syntax:
create property graph graph_name
vertex tables ( table [ key ( column ) ] [ properties ( column [, ...] ) ] [, ...] )
edge tables ( table [ as edge_name ] key ( column )
source key ( column ) references vertex_table ( column )
destination key ( column ) references vertex_table ( column )
[ label label_name ] [ no properties | properties ( ... ) ] [, ...] )ATLAS_GRAPH has customers, agents, products, and tickets as vertices, and three kinds of edges, all defined on TICKETS: RAISED from a customer to a ticket, HANDLED from an agent to a ticket, and ABOUT from a ticket to a product. GRAPH_TABLE then matches a pattern: who raised ticket 9, who handled it, and what it is about.
Example:
create property graph atlas_graph
vertex tables (
customers key (customer_id),
agents key (agent_id),
products key (product_id) properties (product_id, name, category),
tickets key (ticket_id))
edge tables (
tickets as raised key (ticket_id)
source key (customer_id) references customers (customer_id)
destination key (ticket_id) references tickets (ticket_id)
label raised no properties,
tickets as handled key (ticket_id)
source key (agent_id) references agents (agent_id)
destination key (ticket_id) references tickets (ticket_id)
label handled no properties,
tickets as about key (ticket_id)
source key (ticket_id) references tickets (ticket_id)
destination key (product_id) references products (product_id)
label about no properties);
-- who raised ticket 9, who handled it, and what it is about
select *
from graph_table (atlas_graph
match (c is customers) -[is raised]-> (t is tickets) <-[is handled]- (a is agents),
(t) -[is about]-> (p is products)
where t.ticket_id = 9
columns (c.company, a.name as agent, p.name as product));Output:
Property GRAPH created. COMPANY AGENT PRODUCT ________________________ _________________ ________________ Redwood Manufacturing Emma Lindqvist Atlas Billing
PRODUCTS lists its properties explicitly. Without the list, its DESCRIPTION column would become a property, and TICKETS also has a DESCRIPTION of another type; the database refuses a property of the same name with two types (ORA-42414).
Rank Paths by Meaning
GRAPH_TABLE returns matched paths as rows, with the columns you name, and the ticket's embedding can be one of them. This example matches every path from a customer through a ticket to the agent who handled it, and ranks the paths by how similar the ticket is to a new problem.
Example:
-- the paths of the graph, ranked by the meaning of the ticket on them
select g.company, g.plan, g.agent,
round(vector_distance(g.embedding,
vector_embedding(all_minilm_l12_v2 using
'The pipeline board keeps spinning and never shows our deals' as data),
cosine), 3) as distance
from graph_table (atlas_graph
match (c is customers) -[is raised]-> (t is tickets) <-[is handled]- (a is agents)
columns (c.company, c.plan, a.name as agent, t.embedding)) g
order by distance
fetch first 5 rows only;Output:
COMPANY PLAN AGENT DISTANCE ________________________ _______________ ________________ ___________ Ironclad Construction Professional Sofia Marquez 0.306 Halcyon Spa Basic Sofia Marquez 0.31 Marigold Foods Professional Priya Raman 0.408 Vela Travel Professional Yusuf Demir 0.408 Granite Works Basic Daniel Okafor 0.41
Each row is a path: who had a problem like this one, on which plan, and who helped them. The pattern is the graph's work; the ranking is the vector's.
Find Who Else Has This Problem
When a problem is reported, a manager wants its reach: which important customers are affected? This example matches the tickets of Enterprise customers, keeps those within 0.5 of the new problem, and counts them per customer.
Example:
-- which Enterprise customers have reported problems like this one, and how often?
select g.company, count(*) as similar_tickets, max(g.created_at) as latest
from graph_table (atlas_graph
match (c is customers) -[is raised]-> (t is tickets)
where c.plan = 'Enterprise'
columns (c.company, t.created_at, t.embedding)) g
where vector_distance(g.embedding,
vector_embedding(all_minilm_l12_v2 using
'The pipeline board keeps spinning and never shows our deals' as data),
cosine) < 0.5
group by g.company
order by similar_tickets desc;Output:
COMPANY SIMILAR_TICKETS LATEST ____________________ __________________ _______________________ Opal Jewelry 2 11-JUL-2026 09:36:00 Copperline Energy 1 26-MAR-2026 01:07:00
Two Enterprise customers have reported the problem, one of them twice, most recently in July. They are the ones to contact first when the fix ships. Across a large customer base, with more kinds of connections such as accounts, contracts, and integrations, this is where graphs earn their place: the pattern says which connections matter, and the vector says which tickets do.
Graph Query or Joins?
Every query here could be written with joins, since the graph is defined on the same tables. GRAPH_TABLE pays off as patterns grow: paths of several hops, alternative routes, and conditions on both vertices and edges read far more clearly as a MATCH pattern than as a chain of joins. The vector part is the same in both: VECTOR_DISTANCE on a column the query returns.
Conclusion
CREATE PROPERTY GRAPH turns existing tables into vertices and edges without copying data, and GRAPH_TABLE matches patterns such as customer, ticket, and agent, returning the matched paths as rows. Return the ticket's embedding as a column, and VECTOR_DISTANCE ranks or filters those paths by meaning: who had a similar problem, who solved it, and which important customers are affected.
