Learn how to create a graph using SQL views. This document provides step-by-step instructions and code examples for defining views and using them to define node and edge tables. Explore examples with sample code that demonstrate use cases for creating graphs with views. To learn more about using views to create a property graph, including benefits and considerations, see Overview of graphs created from SQL views.
Before you begin
To create a graph, you must:
Ensure your Spanner Graph environment is set up.
Familiarize yourself with how Spanner Graph schemas work.
Create a graph using views
To create a graph using views:
Define views for your graph. Make sure your views follow one of the required view patterns. For more information, see Create a view.
Use your views in the
NODE TABLESandEDGE TABLESclauses of theCREATE PROPERTY GRAPHstatement to create a graph.Include the
KEYclause in theCREATE PROPERTY GRAPHstatement. TheKEYclause specifies the columns from the source view that uniquely identify each graph element.
Example: Create a graph using views
This example creates the following views over Customer and Account tables:
AsiaCustomer, AsiaBankAccount, and AsiaAccountsOwnership. Then, the
example uses these views to create the following in a graph:
Create the
Customernode table using theAsiaCustomerview.Create the
Accountnode table using theAsiaBankAccountview.Create the
Ownsedge table using theAsiaAccountsOwnershipview. This edge connectsCustomernodes withAccountnodes.
Step 1: Create the tables
First, create the data tables. The following code creates the Customer and
Account tables.
CREATE TABLE Customer (
customer_id INT64 NOT NULL,
name STRING(MAX),
address_continent STRING(MAX),
address_country STRING(MAX),
) PRIMARY KEY(customer_id);
CREATE TABLE Account (
account_id INT64 NOT NULL,
customer_id INT64 NOT NULL,
account_type STRING(MAX),
balance INT64,
create_time TIMESTAMP,
address_continent STRING(MAX),
address_country STRING(MAX),
CONSTRAINT FK_CustomerId FOREIGN KEY (customer_id)
REFERENCES Customer (customer_id)
) PRIMARY KEY(account_id);
Step 2: Create the views
Next, create views to transform or filter data from the tables. These views filter the tables to include only customers and accounts in Asia. Views used to create graph elements must ensure that rows in the view are unique.
-- View for 'Customer' nodes, filtered for Asia
CREATE VIEW AsiaCustomer
SQL SECURITY INVOKER AS
SELECT customer.customer_id, customer.name
FROM Customer customer
WHERE LOWER(customer.address_continent) = "asia";
-- View for 'Account' nodes, filtered for Asia.
CREATE VIEW AsiaBankAccount
SQL SECURITY INVOKER AS
SELECT account.account_id, account.balance, account.account_type, account.create_time
FROM Account account
WHERE LOWER(account.address_continent) = "asia";
-- View for 'Owns' edges, connecting customers to accounts in Asia.
CREATE VIEW AsiaAccountsOwnership
SQL SECURITY INVOKER AS
SELECT account.customer_id, account.account_id
FROM Account account
WHERE LOWER(account.address_continent) = "asia";
Step 3: Create the property graph
Now, create the AsiaFinGraph using the views you created. The
CREATE PROPERTY GRAPH statement includes the KEY clause for each graph
element definition to specify columns that uniquely identify the graph elements.
CREATE PROPERTY GRAPH AsiaFinGraph
NODE TABLES (
AsiaCustomer AS Customer KEY(customer_id),
AsiaBankAccount AS Account KEY(account_id)
)
EDGE TABLES (
AsiaAccountsOwnership AS Owns
KEY(customer_id, account_id)
SOURCE KEY (customer_id) REFERENCES Customer (customer_id)
DESTINATION KEY (account_id) REFERENCES Account (account_id)
);
Use cases examples
SQL views offer benefits over using tables for property graph elements. The following examples demonstrate some use cases for defining graph elements with views instead of tables.
Example: Enforce fine-grained graph data access control
To enforce row-level security on your graph data, define your node or edge tables using definer's rights views. The view exposes a permitted subset of the underlying data to the graph
For example, to restrict graph access to only employees in an engineering cost
center, you can create an EngineerEmployeeView view and grant SELECT
permissions on the view to an engineering_data_reader role using the GRANT
clause.
When you define a graph node table using this view, users running graph queries
with the engineering_data_reader role can see only the rows filtered by the
view, which include engineering employees.
-- The table containing all employee data.
CREATE TABLE Employee (
id INT64 NOT NULL,
cost_center STRING(MAX),
job_title STRING(MAX),
office STRING(MAX)
) PRIMARY KEY (id);
-- The definer's rights view that filters for engineering employees.
CREATE VIEW EngineerEmployeeView SQL SECURITY DEFINER AS
SELECT e.id, e.cost_center, e.job_title, e.office
FROM Employee e
WHERE LOWER(e.cost_center) = "engineering";
-- The role that is granted to read the view.
CREATE ROLE engineering_data_reader;
GRANT SELECT ON VIEW EngineerEmployeeView TO ROLE engineering_data_reader;
-- The graph that uses definer's rights view.
CREATE PROPERTY GRAPH EngineeringGraph
NODE TABLES (
EngineerEmployeeView KEY(id)
);
Example: Model derived graph elements
You can use views to define graph elements that require data transformations. A key benefit is that the view defines the transformation, so you don't need to maintain a separate table for the derived data.
For example, you can UNNEST data from an ARRAY column (or an array field
within a JSON column) to model multiple edge relationships from a single row.
In the following supply chain schema example, a Parts table stores a list of
sub-components in a dependent_parts array. A view can use the UNNEST
operator to transform each element of that array into distinct rows. This view
can then serve as an edge table, letting you model a PartDependsOnPart edge to
represent dependency relationships between parts.
-- Parts table with an ARRAY of dependent parts.
CREATE TABLE Parts (
part_id INT64 NOT NULL,
dependent_parts ARRAY<INT64>
) PRIMARY KEY (part_id);
-- A view that unnests the dependent_parts array.
-- GROUP BY ensures uniqueness for the graph element KEY.
CREATE VIEW PartDependsOnPart SQL SECURITY INVOKER AS
SELECT p.part_id, dependent_part_id
FROM Parts AS p,
UNNEST(p.dependent_parts) AS dependent_part_id
GROUP BY p.part_id, dependent_part_id;
-- Graph modeling the part dependency relationship.
CREATE PROPERTY GRAPH SupplyChainGraph
NODE TABLES (
Parts
)
EDGE TABLES (
PartDependsOnPart KEY (part_id, dependent_part_id)
SOURCE KEY (part_id) REFERENCES Parts(part_id)
DESTINATION KEY (dependent_part_id) REFERENCES Parts(part_id)
);
Example: Schemaless data transition
Schemaless data management lets you create a flexible graph definition without predefined node and edge types. While schemaless data management provides flexibility, you might need to transition to a more formal structure as your data becomes more defined. A more formal structure exposes the graph's node and edge relationships, labels, and properties in the schema, which reduces the need for manual data exploration to understand the graph schema.
You can use views to formalize the node and edge types without migrating your
underlying data. For example, you can transition from a typical schemaless model
that uses canonical GraphNode and GraphEdge tables. To do this, you create
views that extract the data from your schemaless tables:
Define a view for each node and edge type you want to formalize (for example,
PersonorWorksFor). In the view, filter the data by its label (for example,WHERE n_label = "person") and cast the properties from the JSON column to specific data types (for example,STRING(prop.name) AS name).Define a new property graph where
NODE TABLESandEDGE TABLESreference the typed views you just created.
A schemaless graph provides better performance than a formalized graph for some queries (for example, a quantified path pattern with multiple edge types). If formalized metadata is important for your use case, then you can use views to transition from a schemaless graph to a typed schema. You can also choose to use a schemaless graph for some use cases and a typed schema graph for other use cases. For more information, see Choose a schema design based on graph queries.
The following example demonstrates the workflow for transitioning from a schemaless to a formalized graph in four steps:
Define the canonical
GraphNodeandGraphEdgetables for the schemaless model.Create an initial, flexible graph on those schemaless tables.
Define typed views (
Person,Company,WorksFor) that extract and formalize the data from the schemaless tables.Create the final, strongly-typed graph that uses these views as its node and edge tables.
-- 1. Create the canonical tables for a schemaless model.
CREATE TABLE GraphNode (
id INT64 NOT NULL,
label STRING(MAX) NOT NULL,
properties JSON
) PRIMARY KEY (id);
CREATE TABLE GraphEdge (
id INT64 NOT NULL,
dest_id INT64 NOT NULL,
edge_id INT64 NOT NULL,
label STRING(MAX) NOT NULL,
properties JSON
) PRIMARY KEY (id, dest_id, edge_id),
INTERLEAVE IN PARENT GraphNode;
-- 2. Define a schemaless graph.
CREATE PROPERTY GRAPH FinGraph
NODE TABLES (
GraphNode
DYNAMIC LABEL (label)
DYNAMIC PROPERTIES (properties)
)
EDGE TABLES (
GraphEdge
SOURCE KEY (id) REFERENCES GraphNode(id)
DESTINATION KEY (dest_id) REFERENCES GraphNode(id)
DYNAMIC LABEL (label)
DYNAMIC PROPERTIES (properties)
);
-- 3. Define typed views that extract and formalize the data.
-- Convert JSON fields to primitive types (for example, INT64, STRING) to
-- ensure type safety.
CREATE VIEW Person SQL SECURITY INVOKER AS
SELECT n.id, STRING(n.properties.name) AS name, INT64(n.properties.age) AS age
FROM GraphNode n WHERE n.label = "person";
CREATE VIEW Company SQL SECURITY INVOKER AS
SELECT n.id, STRING(n.properties.name) AS company_name, BOOL(n.properties.is_public) AS is_public
FROM GraphNode n WHERE n.label = "company";
CREATE VIEW WorksFor SQL SECURITY INVOKER AS
SELECT e.id AS person_id, e.dest_id AS company_id, e.edge_id AS edge_id, STRING(e.properties.since) AS since
FROM GraphEdge e
WHERE e.label = "worksfor";
-- 4. Create the final, formalized graph from the typed views.
CREATE PROPERTY GRAPH typed_formalized_graph
NODE TABLES (
Person KEY(id)
PROPERTIES (name, age),
Company KEY(id)
PROPERTIES (company_name, is_public)
)
EDGE TABLES(
WorksFor KEY(person_id, company_id, edge_id)
SOURCE KEY (person_id) REFERENCES Person(id)
DESTINATION KEY (company_id) REFERENCES Company(id)
PROPERTIES (since)
);
What's next
Learn about the Spanner Graph schema.
Learn about best practices for designing a Spanner Graph schema.