Querying with GRAPH_TABLE and MATCH

Applies to: ✅ Data 360 SQL ✅ Tableau Hyper API

After you define the graph, GRAPH_TABLE finds matching paths and returns them as a table. Use it in FROM like any other table.

The examples on this page show the GRAPH_TABLE portion. Keep the WITH ... AS PROPERTY GRAPH definition in the same statement.

WITH <graph_name> AS PROPERTY GRAPH (...)
SELECT ...
FROM GRAPH_TABLE ( <graph_name>
    MATCH <pattern>
    [ WHERE <condition> ]
    [ ONE ROW PER MATCH
    | ONE ROW PER STEP ( <src_var>, <edge_var>, <dst_var> ) ]
    [ COLUMNS ( <column>[, ...] ) ]
) [ AS <alias> ]

Write the clauses in that order: MATCH, then WHERE, then the result mode, then COLUMNS.

  • <graph_name> must be the graph you just defined. It can't be a Data 360 object, ordinary table, or view. Catalog property graphs aren't supported.
  • If you include COLUMNS, add a table alias (like AS gt).
  • If you omit COLUMNS, every bound variable's properties become output columns, in pattern order.

MATCH: Describe the Path

MATCH is the pattern you want to find. Parentheses are vertices. Dashes are edges. See Path Patterns and Quantifiers for more on direction and hops.

  • -[]-> walks from left to right.
  • <-[]- walks from right to left.
  • -[]- walks either way.
MATCH (i:individual)-[:customerOrder]->(order:salesOrder)

That means: bind the variable i to vertices with the individual label, follow a customerOrder edge, and bind order to the destination vertex with the salesOrder label.

Build a pattern in this order.

  1. () matches any vertex.
  2. ()-[]->() matches any two vertices connected by a rightward edge. Use <-[]- for left and -[]- for either way.
  3. Add labels: (i:individual)-[:customerOrder]->(order:salesOrder).
  4. Use the bound name to read properties: i.name, order.orderId.
  5. Use a local WHERE to filter that one element: (i:individual WHERE i.name = 'Avery').
  6. Chain more hops to follow a longer path, or separate independent patterns with commas.
MATCH (i:individual)-[:customerOrder]->(order:salesOrder)   -- one path
MATCH (i:individual), (product:product)                    -- two separate vertices

How to Read Properties

When a pattern matches a record, you give that match a name. Then you read its fields through the name.

(i:individual) means: find an Individual and call it i.

i.name means: use the name property on that customer.

The property name is the name from the graph definition. It doesn't have to match the DMO field name.

In the commerce graph:

Object Object field Use this in the query
Individual ssot__Id__c i.individualId
Individual ssot__FirstName__c i.name
Sales Order ssot__Id__c order.orderId
Sales Order ssot__Name__c order.name
Goods Product ssot__Id__c product.productId
Goods Product ssot__Name__c product.name
Sales Order Product ssot__CreatedDate__c line.createdDate
Sales Order Product ssot__OrderedQuantity__c line.quantity

Use those names in WHERE and COLUMNS. Don't use the raw ssot__... names unless the graph exposed the columns as-is.

WHERE: Filter the Path

Use an element-local WHERE to filter one customer, order, or line item. Use a global WHERE when the condition compares more than one of them.

This query keeps Avery's orders that include more than one unit.

WITH pg AS PROPERTY GRAPH (...)
SELECT * FROM GRAPH_TABLE(pg
    MATCH (i:individual)-[:customerOrder]->(:salesOrder)
        -[line:orderProduct]->(product:product)
    WHERE i.name = 'Avery' AND line.quantity > 1
) AS gt;

This version puts each filter next to the vertex or edge it applies to.

WITH pg AS PROPERTY GRAPH (...)
SELECT * FROM GRAPH_TABLE(pg
    MATCH (i:individual WHERE i.name = 'Avery')
        -[:customerOrder]->(:salesOrder)
        -[line:orderProduct WHERE line.quantity > 1]->(product:product)
) AS gt;

A local WHERE needs a bound name, so you can't attach one to (:product). On a repeated edge, that local filter applies to every hop. A global WHERE runs before COLUMNS, so it can't use column aliases.

COLUMNS: Choose the Result Fields

COLUMNS is the result table you want back. Each item is one of these.

COLUMNS (
    <variable>.<property> [AS <alias>],
    <expression> AS <alias>,
    <variable>.*,
    <variable>.* EXCLUDE ( <property>[, ...] )
)
  • variable.property — the alias defaults to the property name.
  • Any SQL expression — AS is required.
  • variable.* — every property on that variable.
  • variable.* EXCLUDE (...) — every property except the ones you list.

Use AS when you rename a column. An alias without AS is a syntax error. The outer SELECT can use only the columns you list.

WITH pg AS PROPERTY GRAPH (...)
SELECT gt.individual_name, gt.product_name, gt.ordered_quantity
FROM GRAPH_TABLE(pg
    MATCH (i:individual)-[:customerOrder]->(:salesOrder)
        -[line:orderProduct]->(product:product)
    COLUMNS (
        i.name AS individual_name,
        product.name AS product_name,
        line.quantity AS ordered_quantity
    )
) AS gt;

You can also project every property on a variable with i.*, or hide some of them with i.* EXCLUDE (individualId). If that variable can match more than one element table, the star expands to every property those element tables expose. See Cross-Label Property Access.

Examples

These examples use the commerce graph from Defining a Property Graph.

Find a Customer

WITH pg AS PROPERTY GRAPH (...)
SELECT gt.individual_name
FROM GRAPH_TABLE(pg
    MATCH (i:individual WHERE i.individualId = 'I-1001')
    COLUMNS (i.name AS individual_name)
) AS gt;

List Products on an Order

WITH pg AS PROPERTY GRAPH (...)
SELECT gt.individual_name, gt.product_name, gt.createdDate, gt.quantity
FROM GRAPH_TABLE(pg
    MATCH (i:individual)-[:customerOrder]->(:salesOrder)
        -[line:orderProduct]->(product:product)
    COLUMNS (
        i.name AS individual_name,
        product.name AS product_name,
        line.createdDate,
        line.quantity
    )
) AS gt;

Return Every Property on the Customer

WITH pg AS PROPERTY GRAPH (...)
SELECT gt.*
FROM GRAPH_TABLE(pg
    MATCH (i:individual)-[:customerOrder]->(:salesOrder)
        -[line:orderProduct]->(product:product)
    COLUMNS (i.*, line.createdDate)
) AS gt;

Related Documentation