SAP HANA Graph Reference en
SAP HANA Graph Reference en
SAP HANA Graph Reference en
2 Introduction. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 5
4 Graph Workspaces. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 7
4.1 Create and Drop Graph Workspaces. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 7
4.2 Export and Import Graph Workspaces. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 9
4.3 Graph Metadata Views. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 9
4.4 Cache Configuration. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 10
6 GraphScript Language. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 13
6.1 Integration into SAP HANA's Stored Procedure Environment. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 13
6.2 Language Fundamentals. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 14
6.3 Graph Primitive Types and Operations. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .19
Graph Primitives. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 19
Basic Graph Operations. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 20
Basic Vertex Operations. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 22
Basic Edge Operations. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 23
Basic Weighted Path Operations. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 24
Built-In Graph Algorithms. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 25
Graph Traversal Statements. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 32
6.4 Container Types and Operations. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 34
MULTISET. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .35
SEQUENCE. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 37
6.5 Table Operations. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 39
6.6 Scalar Data Types and Operations. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 41
Numeric Types. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .41
Non-Numeric Scalar Types. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 42
Typed Literals. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 43
Type Casts. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 44
Arithmetic Expressions. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 45
String Functions. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 45
Time Functions. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 46
Boolean Expressions. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 47
8 Graph Algorithms. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 66
8.1 Neighborhood Search (Breadth-First Search). . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 66
8.2 Shortest Path. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 68
Shortest Path (One-to-All). . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 68
Shortest Path (One-to-One). . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 72
8.3 Strongly Connected Components. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 74
8.4 Graph Algorithm Variables. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 75
8.5 Pattern Matching. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 77
Query Language. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 77
9 Additional Information. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 79
9.1 Appendix A - Open Flights Graph Example. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .79
9.2 Appendix B - Notation. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 81
9.3 Appendix C - GraphScript Cheat Sheet. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 83
9.4 Appendix D - SAP HANA Graph Viewer. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 91
Install SAP HANA Graph Viewer. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 91
This reference provides information about SAP HANA Graph. It is organized as follows:
● Introduction
Introduction to SAP HANA Graph.
● SAP HANA Graph Data Model
Description of SAP HANA Graph data model using a simple example.
● Graph Workspaces
Description of SQL statements for creating and manipulating graph workspaces.
● Graph Data Modification
Description of SQL statements for modifying graph data.
● GraphScript Language
Description of the GraphScript stored procedure language.
● openCypher Query Language
Description of the openCypher query language interface in SAP HANA (Cypher is a registered trademark of
Neo4j, Inc.).
● Graph Algorithms
Description of supported graph algorithms in SAP HANA calculation scenarios.
● Additional Information
A collection of additional information.
SAP HANA Graph is an integral part of the SAP HANA core functionality. It expands the SAP HANA platform
with native support for graph processing and enables the execution of typical graph operations on the data
stored in an SAP HANA system.
Graphs are a powerful abstraction that can model different kinds of networks and linked data coming from
many industries, such as logistics and transportation, utility networks, knowledge representation, and text
processing.
In SAP HANA, a graph is a set of vertices and a set of edges. Each edge connects two vertices; one vertex is
denoted as the source and the other as the target. Edges are always directed. Any number of edges may
connect the same two vertices. Vertices and edges can have an arbitrary number of attributes. An attribute
consists of a name that is associated with a data type and a value.
The primary storage of a graph is two relational objects that can be tables or views. These objects are called the
vertex table and edge table. The vertex table stores the set of vertices and the edge table stores the set of
edges. Vertex attributes correspond to columns of the vertex table. Similarly, edge attributes correspond to
columns of the edge table. The maximum number of attributes is bound by the maximum number of columns
for the underlying tables (for more information see SAP HANA SQL Reference Guide).
One vertex attribute or a set of vertex attributes (called the vertex key) must uniquely identify vertices. One
edge attribute or a set of edge attributes (called the edge key) must uniquely identify edges.
The edge table contains at least two additional columns that reference the key column of the vertex table. One
of the columns identifies the source vertex and the other identifies the target vertex of an edge. If the vertex key
consists of multiple attributes, then the edge table's source and target must consist of a corresponding set of
attributes.
Relational storage allows the whole feature set of SAP HANA to be applied to the graph data: access control,
backup and recovery, and so on. It also allows all SAP HANA Graph functions to be applied to the graph data
stored in relational format coming from business applications. SAP HANA Graph provides a dedicated catalog
object, which is referred to as a graph workspace, for defining a graph in terms of the existing SAP HANA
tables.
Related Information
A graph workspace is a catalog object that defines a graph in terms of tables and columns.
● Vertex table
● Edge table
● Key column(s) in the vertex table
● Key column(s) in the edge table
● Source vertex column(s) in the edge table
● Target vertex column(s) in the edge table
A graph workspace is uniquely identified by the database schema it resides in and the workspace name. An
SAP HANA instance can contain multiple graph workspaces in the same schema with different workspace
names or different database schemas.
Related Information
SAP HANA Graph provides SQL extensions for creating and dropping graph workspaces.
Before you create a graph workspace, make sure that the underlying tables, views, or synonyms for vertices
and edges exist. The following SQL statements create a vertex table named NODES and an edge table named
EDGES in the FLIGHTS schema:
After you create the necessary tables, you can create a graph workspace named GRAPH in the FLIGHTS
schema by running the following statement:
The vertex table, edge table, and graph workspace can reside in different schemas. If any of the schemas are
omitted, then the default schema is assumed.
The columns of the edge table and the vertex table are interpreted correspondingly as edge and vertex
attributes. In this example, the vertices in the "FLIGHTS"."NODES" table have the attributes "TYPE", "NAME",
"CITY", "COUNTRY", and "LOCATION", which all may contain NULL values. A row in the vertex table or the
edge table is interpreted correspondingly as a vertex or an edge.
The vertex and edge key columns can be of one of the following SQL types: TINYINT, SMALLINT, INTEGER,
BIGINT, or NVARCHAR. The INTEGER or BIGINT integer type is recommended. Furthermore, the NOT NULL
and UNIQUE flags are mandatory if keys consist of a single column.
During the creation of a new graph workspace, the SAP HANA system checks that all specified tables and
columns exist and have supported data types. A newly created graph workspace is valid as long as the
specified columns and tables exist and fulfill the data types and type flags requirements. Source and target
columns must have the same data types as the vertex key columns, and a NOT NULL flag if the vertex key
consists of a single column.
A valid graph workspace is consistent if both the source and target columns contain existing values from the
vertex key column. In the CREATE statements listed above, the referential constraints (REFERENCES)
guarantee the consistency of the workspace.
An existing graph workspace named GRAPH in the FLIGHTS schema can be deleted with the following
statement:
Creating or dropping graph workspaces does not modify the content of the underlying vertex and edge tables.
To create a graph workspace, you need the CREATE ANY privilege for the intended schema and the SELECT
privilege for both the vertex and edge tables. To drop a graph workspace, you must be the creator of the graph
workspace or must have the DROP privilege for the given graph workspace.
Related Information
Graph workspace objects can be exported from or imported into an SAP HANA system using the existing
export and import SQL commands.
Exporting or importing a schema automatically exports or imports all graph workspaces contained in that
schema. For the full set of options for IMPORT and EXPORT commands, see the SAP HANA SQL Reference
Guide. The vertex and edge tables are by default exported together with a graph workspace unless the NO
DEPENDENCIES parameter is used.
Assuming the database instance is installed under /usr/sap/HDB/HDB00, the following statement exports
the graph workspace "FLIGHTS"."GRAPH" together with the vertex table "FLIGHTS"."NODES" and the edge
table "FLIGHTS"."EDGES" to /usr/sap/HDB/HDB00/work
The following statement imports the graph workspace "FLIGHTS"."GRAPH" together with the vertex table
"FLIGHTS"."NODES" and the edge table "FLIGHTS"."EDGES" from /usr/sap/HDB/HDB00/work:
Related Information
Structure
Created graphs may be temporarily stored in SAP HANA's common cache framework for optimizing system
responsiveness while still guaranteeing transactionally correct results. In addition to this, there are possibilities
to analyze the cache.
Related Information
Any change to the edge table or the vertex table affects the edges or the vertices of the graph.
The following SQL statements create two new vertices with vertex keys PEK (Beijing) and TNA (Jinan), and an
edge between them in the "FLIGHTS"."GRAPH" workspace. For the complete list of statements for creating the
example graph in Create and Drop Graph Workspaces [page 7], see Appendix A - Open Flights Graph Example
[page 79].
Vertices can be modified and deleted using SQL UPDATE and DELETE statements. The following statement
modifies the "COUNTRY" attribute of all vertices with "COUNTRY" 'China'.
The following statement deletes those edges from the graph workspace "FLIGHTS"."GRAPH" that contain 'FRA'
as "SOURCE" or "TARGET".
Vertices can be inserted, updated, and deleted in the same way as edges.
If the consistency of a graph workspace is not guaranteed by referential constraints, modifications of the
referenced graph tables can lead to an inconsistent graph workspace. The exact behavior in case of
inconsistent graph workspaces is different for each Graph Engine component. See Create and Drop Graph
Workspaces [page 7].
The uniqueness of vertices in the "FLIGHTS"."GRAPH" workspace can be checked with the following query on
the vertex table:
If the result of above query is not empty, then the vertex key column ("NODE_KEY") contains duplicates and
the graph workspace is inconsistent.
The correctness of the source and target vertex references can be checked with the following query:
If the result of the above query is not empty, then either the source or target of the resulting edge is not a valid
vertex key, leading to an inconsistent graph workspace.
GraphScript is an imperative programming language that provides application developers with a high-level
interface for accessing the graph data defined by a graph workspace.
The GraphScript language eases the development of application-specific graph algorithms and integrates
them into SQL-based data processing. Furthermore, GraphScript provides optimized built-in algorithms to
solve common graph-related problems, such as finding the shortest path from one vertex to another. These
algorithms are available as built-in functions that can be reused in any GraphScript program to simplify the
development of efficient solutions for customer-specific, graph-related problems.
GraphScript procedures support debugging from the SAP HANA Database Explorer.
See SAP HANA Modeling Guide for SAP Web IDE for SAP HANA.
The mandatory language identifier for GraphScript procedures is GRAPH. Procedure parameters can be IN,
OUT, or INOUT, and their data type must be supported by GraphScript. The default value of output parameter
variables is NULL. If tables are used as a parameter, then their table types must be created before they are
used as parameter. Inline definitions of table types in the parameter list are not permitted. If a table is used as
INOUT or OUT, it cannot have foreign key or NOT NULL constraints.
Example
The GraphScript grammar consists of basic language elements, supports variables, and provides options for
specifying the control flow.
Grammar
Statements
<statement> ::=
<definition>
| <assignment>
| <conditional>
| <foreach_loop>
| <temp_attribute>
| <while_loop>
| <traversal>
| <end_traversal>
Expressions
<expr> ::=
<literal_expr>
| <attr_access_expr>
| <local_var_expr>
| <arithmetic_expr>
| <relational_expr>
| <logical_expr>
| <collection_init_expr>
| <function_expr>
| <set_operation>
| <concat_expr>
| <index_expr>
| <cell_expr>
| <filter_expr>
| <proj_expr>
| <clos_expr>
Terminal Symbols
The following list summarizes special characters and symbols that are used in GraphScript.
<comma> ::= ,
<single_quote> ::= '
<double_quote> ::= "
<l_paren> ::= (
<r_paren> ::= )
<l_curly> ::= {
<r_curly> ::= }
<l_square> ::= [
<r_square> ::= ]
<pipe> ::= ||
<semicolon> ::= ;
<colon> ::= :
<dot> ::= .
<equals> ::= =
<minus> ::= -
<plus> ::= +
<lower> ::= <
<lower_equal> ::= <=
<greater> ::= >
<greater_equal> ::= >=
<leads_to> ::= =>
<equal> ::= ==
<unequal> ::= !=
<membership_in> ::= IN
<membership_not_in> ::= NOT IN
<underscore> ::= _
<asterisk> ::= *
<slash> ::= /
<modulo> ::= %
<any_character> ::= !! any character
<hash_symbol> ::= #
<dollar_sign> ::= $
<digit> ::= 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9
<pos_digit> ::= 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9
<letter> ::= a | b | c | d | e | f | g | h | i | j | k | l | m | n | o | p | q |
r | s | t | u | v | w | x | y | z | A | B | C | D | E | F | G | H | I | J |
K | L | M | N | O | P | Q | R | S | T | U | V | W | X | Y | Z
A single-line comment starts with "--"; all characters that follow in the line are treated as a comment. A
multiline comment is enclosed in "/*" and "*/".
Examples
FOREACH e IN Edges(:g) {
/* this is a multi line comment
INTEGER i = :e.attr;
INTEGER v = 23;*/
}
Local Variables
GraphScript supports local variables that split large and complex statements into smaller ones, improving the
script's overall readability. After initial assignment or declaration (see Assignments [page 17]), the type of a
variable can no longer be modified. A local variable expression can be used anywhere that an expression is
supported, as long as the corresponding expression types match. The names of variables are case insensitive.
Variable references that are used for read access must be preceded by a colon (:), while references for write
access have no leading colon.
Examples
aVariable
aSecondVariable12
:aVariable
Definition Statements
A definition statement declares and defines a local variable of a specific type. Objects of primitive types are
default-initialized to NULL. Additionally, it’s possible to do this explicitly by using NULL. Vertices, edges, and
graphs have to be initialized in the declaration. A variable is visible and accessible in the current scope and all
inner scopes, such as in loops and conditional statements. Variables defined inside loops and conditional
statements aren’t accessible outside the statements. GraphScript doesn’t support variable shadowing; in other
words, a variable defined in an outer scope can’t be redefined in an inner scope.
Examples
GRAPH g1 = GRAPH("FLIGHTS","GRAPH");
GRAPH g2 = GRAPH("GRAPH");
GRAPH g3 = GRAPH(mygraph);
VERTEX v = VERTEX(:g1,1);
EDGE e = EDGE(:g1,'3');
INTEGER i;
DOUBLE d = 23.5;
VARCHAR s = 'Dave';
NVARCHAR s = N'Dave';
Assignments
An assignment statement binds the result of an expression to a local variable. Alternatively, if the left-hand side
of the assignment statement is an attribute access expression, the value of the right-hand side expression is
assigned to the corresponding attribute.
GraphScript is statically typed and the data type of the object that is bound to the variable can’t change during
the lifetime of a single query run. Only variables of primitive types can be set to NULL. All variables have to be
initialized before they can be referenced or accessed in a GraphScript expression.
Examples
GRAPH g = GRAPH("MYWORKSPACE");
INTEGER i;
i = 23;
VERTEX v = VERTEX(:g,1);
v.attr = 23;
Identifiers
GraphScript uses identifiers to reference schema names, graph workspace names, and attribute names.
Identifiers can look like VARCHAR/NVARCHAR instances, but they’re different from them and aren’t
interchangeable with them.
A conditional statement consists of an IF body and an optional ELSE body. Each body contains an arbitrary
number of statements enclosed in curly braces. If the expression <expr> in the IF branch evaluates to TRUE,
the corresponding statements in the IF body are executed, otherwise the statements in the ELSE branch are
executed.
Examples
INTEGER i;
IF (2 < 3) {
IF (TRUE) {
i = 5;
} ELSE {
i = 17;
}
}
FOREACH Loops
A FOREACH loop iterates over a container (Multiset, Sequence). The iteration order isn’t specified and can’t be
assumed to be the same for two different script executions. The statements in the loop body can reference the
defined variable in the loop header. The scope of this variable is limited to the inner body of the loop statement;
in other words, the variable can no longer be referenced outside the loop statement. Within a FOREACH loop,
the keywords BREAK or CONTINUE can be used to stop loop execution or skip to the next iteration,
respectively. For FOREACH loop statements on sequence containers, an optional ordinal variable can be used
to access the ordinal position of the element currently being processed. Additionally, a FOREACH loop
statement can be used to iterate over the result of the STRONGLY_CONNECTED_COMPONENTS function,
which is a multiset of multiset of vertices.
Examples
GRAPH g = GRAPH("MYWORKSPACE");
FOREACH v IN { VERTEX(:g,1), VERTEX(:g,2) } {
INT a = :v.attr;
}
FOREACH v IN [ VERTEX(:g,1), VERTEX(:g,2) ] WITH ORDINALITY AS i {
INTEGER a = :i;
}
FOREACH v IN [ 1, 2, 3, 4 ] {
INTEGER a = :i;
}
A WHILE loop repeats the statements specified in the loop body as long as the condition in the loop head
evaluates to true. Within a WHILE loop, the keywords BREAK and CONTINUE can be used. BREAK stops the
execution of the loop and CONTINUE skips to the next loop iteration.
Examples
INTEGER a = 10;
WHILE (:a > 0) {
a = :a - 1;
}
a = 10;
INTEGER b = 3;
WHILE (:a > 0) {
a = :a - 1;
IF( a % 2 == 0 ) {
CONTINUE;
}
b = :b - 1;
IF(:b == 0) {
BREAK;
}
}
● GRAPH
A GRAPH variable specifies a structured collection of vertices and edges.
A graph refers to a graph workspace catalog object specified by workspace name, an inverse graph for an
already-defined graph, or a subgraph of an already-defined graph. Alternatively, a graph can be created
from two input tables containing vertices and edges.
You must initialize a GRAPH variable at the time of declaration. There's no default initialization for GRAPH
variables.
● VERTEX
The VERTEX data type specifies a node entity in the graph.
An existing vertex object can be retrieved from a graph workspace using its key. Supported key types are
INTEGER, BIGINT, VARCHAR, and NVARCHAR. The creation of new vertices within GraphScript isn’t
supported.
You must initialize a VERTEX variable at the time of declaration. There’s no default initialization for VERTEX
variables.
Constructors
Creates a graph object based on the specified workspace in the specified schema. If the schema parameter is
omitted, then the SQL schema inference rules apply.
Creates a graph object based on the specified edge and vertex tables, which are passed as arguments to the
GraphScript procedure. Besides the edge and vertex table variables, the column identifiers of edge source,
edge target, edge key, and vertex key need to be specified.
Examples
VERTICES
EDGES
A temporary attribute can be used to store vertex-centric or edge-centric state information at script runtime.
Read access to temporary attributes is the same as for persistent attributes; write access is only allowed for
temporary attributes.
If no initialization of the new attribute is defined, the default value is 0 for numeric types and the empty string
for strings.
Examples
Constructors
Constructs a vertex reference from a graph and scalar vertex key. If no vertex with the given key exists, then the
program terminates with an error.
VERTEX_EXISTS
Checks if a vertex with the given vertex key exists in a graph or a weighted path.
IN_DEGREE
OUT_DEGREE
DEGREE
EDGES
IN_EDGES
OUT_EDGES
An attribute access expression allows you to retrieve the corresponding attribute value for a given vertex
variable and attribute name. The attribute name is an identifier. The return type of the expression is derived
from the underlying specified attribute type.
Examples
Constructors
SOURCE
TARGET
An attribute access expression allows you to retrieve the corresponding attribute value for a given edge
variable and attribute name. The attribute name is an identifier. The return type of the expression is derived
from the underlying specified attribute type.
Examples
(Constructors)
WEIGHTEDPATH objects can’t be constructed directly but are the result of several built-in graph algorithms.
LENGTH
VERTICES
EDGES
Edges Between
Returns all edges between a start set or vertex and a target set or vertex in a graph.
Is Reachable
Tests for the existence of at least one path from vertex v1 to vertex v2.
Inverse Graph
Returns the inverse graph of the given parent graph. All vertices of the parent graph are copied into the
resulting inverse graph without any modification. All edges of the parent graph are copied into the resulting
inverse graph with swapped edge direction. The values for all vertices as well as edge attributes are copied
from the parent graph. Attribute handling is identical to subgraphs.
On inverse graphs, the SOURCE(:e) and TARGET(:e) functions return the inverse result, whereas accessing
the edge's source and target key attributes returns the original values.
Examples
In the following example, we manually construct a multiset neighborsFRA of all direct neighbors of FRA
independently of the edge direction using INVERSEGRAPH. Note that we use a FOREACH loop to get the
corresponding vertices in Graph G by key, as using the UNION operation for multisets from different graphs
isn’t permitted.
This example is an artificial one for the sake of demonstrating the INVERSEGRAPH function. The same result
could be achieved much more efficiently by calling the NEIGHBORS function with a distance window from -1 to
1.
Returns the subgraph of the given parent graph induced by the given container of vertices. The subgraph
contains a copy of all vertices in the input vertex container as well as all edges of the parent graph whose
source and target are both in the given vertex container.
Returns the subgraph of the given parent graph induced by the given container of edges. The subgraph
contains a copy of the given edges as well as all source and target vertices of the given edge container.
All vertices and edges of a subgraph originate from the parent graph but are different objects. A vertex or edge
of a subgraph has all persistent and temporary attributes of a vertex or edge in the parent graph. Modifications
of temporary attributes in the parent graph aren’t propagated to the corresponding temporary attributes of a
subgraph and vice versa.
Examples
The following example demonstrates the usage of the subgraph function in combination with temporary
attributes. The temporary attribute continent is defined on graph g_flights before deriving the subgraph
g_EuropeanFlights from g_flights. Thus, it’s available in both graphs. As the temporary attribute
weather is added to g_flights after creating g_EuropeanFlights, accessing this vertex attribute for a
vertex of g_EuropeanFlights leads to an error, as demonstrated. We can, however, add a vertex attribute
with the same name and type to g_EuropeanFlights, rendering the previously erroneous statement valid.
Later on, although vertices v_frankfurtEUR and v_frankfurt share the same key, they are two separate
objects and can have different values for the temporal attribute weather.
Explores the vicinity of a given set of start vertices with a distance window and optional edge direction.
<neighbors_function> ::=
NEIGHBORS '(' <parent_graph_variable>, <start_vertices>,
<lower_bound>, <upper_bound> [, <edge_direction>] ')'
<parent_graph_variable> ::= <variable_reference>
<start_vertices> ::= <expr>
<lower_bound> ::= <expr>
<upper_bound> ::= <expr>
<edge_direction> ::= <expr>
Start vertices can be either a single vertex expression, or expressions returning a multiset or sequence of
vertices.
In the following section, we define the distance of a vertex V to the start_vertices set as the length (counted in
hops) of the shortest of all paths from any member of the start_vertices set to V.
For non-negative lower_bound and upper_bound values, the NEIGHBORS function returns any vertex whose
distance to the start_vertices set isn’t smaller than the lower_bound value and not larger than the
upper_bound value.
The optional edge direction parameter can be used to specify which edges the algorithm traverses when
evaluating the distance of a vertex to the start_vertices set. The following values are possible:
'OUTGOING' traverses the edges as given in the input graph. 'INCOMING' traverses the edges of the input
graph in reverse direction. 'ANY' traverses the input graph as if it was undirected.
When the optional direction parameter isn’t used, negative lower_bound and/or upper_bound values compute
the result as described following:
● If both lower_bound and upper_bound are negative, that is, NEIGHBORS(:g, :v, -a, -b) is called, the
function computes the distance processing the edges in reverse direction and adjusted interval borders:
NEIGHBORS(:g, :v, -a, -b) returns the same result as NEIGHBORS(:g, :v, b, a,
'INCOMING').
● If lower_bound is negative and upper_bound is non-negative, that is, NEIGHBORS(:g, :v, -a, b) is
called, then edges are traversed in both outgoing direction (up to b hops) and in incoming direction (up to a
hops). NEIGHBORS(:g, :v, -a, b) returns NEIGHBORS(:g, :v, a, 0) UNION
NEIGHBORS(:g, :v, 1, b).
The computation performed in the example of the INVERSEGRAPH function can be rewritten using a single
NEIGHBORS call with a corresponding distance range:
If the direction parameter is used, negative bound values are treated as 0. Any bounds interval for which the
upper bound is smaller than the lower bound returns an empty result.
Returns a WEIGHTEDPATH instance containing a shortest path within the given parent graph (first parameter)
from a start vertex (second parameter) to a target vertex (third parameter). By default, the weight metric of the
SHORTEST_PATH built-in function is the hop distance, but it’s also possible to supply a custom weight function
as a closure expression (optional fourth parameter).
The weight function takes an edge as parameter and returns a value of a numerical type: INTEGER, BIGINT, or
DOUBLE. The return type matches the WEIGHTEDPATH weight type. The weight function may contain only a
single statement, which needs to be a RETURN statement. Furthermore, it is only possible to return literals or
to perform edge attribute access. It is currently not possible to access variables defined outside the weight
function.
Like a subgraph, the WEIGHTEDPATH contains copies of the corresponding vertices and edges from the parent
graph. All vertices and edges of a WEIGHTEDPATH originate from the parent graph but are different objects. A
vertex or edge of a WEIGHTEDPATH has all persistent and temporary attributes of a vertex or edge in the
parent graph at the time of path creation. Modifications of temporary attributes in the parent graph aren’t
propagated to the corresponding temporary attributes of a WEIGHTEDPATH and the other way around.
It’s possible to define temporary attributes for the vertices and edges of a path.
The edge direction is an optional string parameter to control how the SHORTEST_PATH function treats the
direction of edges in the given input graph. Three values are possible: 'OUTGOING', 'INCOMING', and 'ANY'.
'OUTGOING' is the default and specifies that the edges' direction is treated exactly as given in the input graph.
'INCOMING' means the edges' direction is considered reversed during SHORTEST_PATH search. This is like
running SHORTEST_PATH on the inverse input graph. 'ANY' specifies that SHORTEST_PATH ignores the edge
direction and works like it’s running on an undirected graph.
Examples
The following example demonstrates the usage of the SHORTEST_PATH function. For a more in-depth
explanation of the semantics for temporary attributes of vertices and edges in a path, see the previous
subgraph example.
The following example demonstrates how to use the edge direction parameter to let the SHORTEST_PATH
function work as if it was operating on a graph with undirected edges.
Returns a subgraph of the given parent graph (first parameter) built from the shortest paths from the start
vertex (second parameter) to all other reachable vertices.
It contains all the attributes from the parent graph and an additional vertex attribute (third parameter)
containing the distance from the start vertex to each reachable vertex. The type of the distance attribute is
either BIGINT or the return type of the optional weight function. By default, the weight metric of the
SHORTEST_PATHS_ONE_TO_ALL built-in function is the hop distance, that is, the number of edges on the
path, but it’s also possible to supply a custom weight function (optional fourth parameter). For details on the
weight function see Shortest Path [page 29].
The optional edge_direction parameter can be used to control how the direction of the edges of the input graph
is treated by the shortest path search. By default, the algorithm processes edges according to their original
direction as given in the input graph. For possible values and discussion of the edge direction parameter, see
Shortest Path [page 29].
The resulting subgraph is a tree, that is, a directed, acyclic graph where each vertex has only one incoming
edge, except for the start vertex, which has no incoming edge.
Examples
The following example demonstrates the usage of the SHORTEST_PATHS_ONE_TO_ALL function.
The following example demonstrates the use of custom weight functions of various types. The first graph is
constructed using a weight function depending on a temporary edge attribute. The second graph uses a fixed
constant weight. The third graph is based on a nontemporary edge attribute.
The following example demonstrates how to use the edge direction parameter to let the
SHORTEST_PATHS_ONE_TO_ALL function work as if it was operating on a graph with undirected edges.
K-shortest Paths
Returns a sequence of WEIGHTEDPATH instances containing the num_paths (fourth parameter) shortest
paths within the given parent graph from a start vertex (second parameter) to a target vertex (third parameter).
By default, the weight metric of the K_SHORTEST_PATHS built-in function is the hop distance, but it's also
possible to supply a custom weight function (optional fourth parameter). See Shortest Path [page 29] for
details on the weight function. The function creates paths that might contain cycles. The paths in the sequence
are ordered by increasing length.
Examples
The following example demonstrates the usage of the K_SHORTEST_PATHS function.
The following example demonstrates the use of a custom weight function of various types.
Returns a multiset of multisets of vertices, representing the strongly connected components in the parent
graph. The foreach loop statement can be used to iterate over the result and access the individual components.
Each strongly connected component is represented as a multiset of vertices and can be used in the same way
as any other multiset of vertices.
Examples
The following example demonstrates the usage of the strongly connected components function. The result of
the function is a container of containers. The built-in function COUNT can be used to determine the total
number of strongly connected components in the result. One can iterate over the result and use a temporary
vertex attribute to store the component number to which the vertex belongs.
Traversal statements explore a graph in a breadth-first or depth-first manner. They allow operations to be
performed at each visit of a vertex or an edge during the traversal. If there's depth-first traversal, it's also
possible to specify operations at each vertex exit. The blocks of operations to be performed at such visits are
The optional second parameter of type BIGINT corresponds to the traversal depth and is only valid for the
breadth-first traversal. The traversal depth is zero-based, that is, the start vertex or vertices have the traversal
depth of 0.
Variables defined outside a traversal hook can be accessed and modified within the hook.
The visit vertex hook is executed when first encountering a node. The visit edge hook will be executed
immediately before the visit node hook execution of the target node.
The END TRAVERSE ALL statement is only valid inside a traversal hook. When executed, the traversal is
terminated. If there's BFS traversal, it means that no further levels of vertices or edges of the graph are
explored. However, all hooks corresponding to vertices or edges on the current level are still completely
executed.
The END TRAVERSE statement is only valid inside a traversal hook. When executed, the traversal is stopped at
the current vertex or edge. In case of BFS traversal, this means the following:
● If END TRAVERSE is called from a vertex hook, then all outgoing edges of that vertex are ignored.
● If END TRAVERSE is called from an edge hook, then the target vertex of that edge is not reached using this
edge. However, it's still possible to reach the target vertex by a different edge.
A container is a composite value comprising zero or more elements of the same type. Containers are typically
used for temporarily holding and processing intermediate results.
GraphScript offers two container types: MULTISET and SEQUENCE. Both container types support the following
data types: VERTEX, EDGE, INTEGER, BIGINT, DOUBLE, TIMESTAMP, NVARCHAR, and BOOLEAN.
The element type is a part of the type specification and is written in angular brackets after the MULTISET or
SEQUENCE keyword.
<multiset_type> ::=
MULTISET '<' <vertex_or_edge> '>'
| MULTISET '<' <primitive_type> '>'
| MULTISET '<' MULTISET '<' VERTEX '>' '>'
<sequence_type> ::=
SEQUENCE '<' <vertex_or_edge> '>'
| SEQUENCE '<' <primitive_type> '>'
Both container types can be used in FOREACH statements, filter expressions, and projection expressions.
There are also container-specific element types and operations.
Containers of vertices or edges can only store elements from a single graph. Container variables cannot be
reassigned to containers with elements from another graph.
6.4.1 MULTISET
A multiset is an unordered container, and there is no ordinal position to reference individual elements of a
multiset.
The elements of a multiset can be multisets of vertices. However, this is limited to the result of the strongly-
connected component algorithm. Currently, operations on multisets of multisets are limited compared to
multisets of other element types.
Constructors
Variables of type MULTISET can be initialized with a comma-separated enumeration of elements within curly
brackets.
INTEGER x = 13;
MULTISET<INTEGER> m1 = { 5, 1, 5, :x, 13 };
By default, a multiset of a primitive type (INTEGER, BIGINT, DOUBLE, TIMESTAMP, NVARCHAR, and
BOOLEAN) is initialized as empty.
MULTISET<DOUBLE> m2;
An empty multiset of a primitive type can also be initialized explicitly with the multiset constructor.
MULTISET<BIGINT> m3 = MULTISET<BIGINT>();
An empty multiset of VERTEX or EDGE type requires a graph variable for initialization.
DISTINCT
COUNT
Returns the size of the given multiset. The result type is BIGINT.
SEQUENCE
Returns a sequence containing elements from the given multiset. The order of elements in the resulting
sequence is arbitrary.
Set Operations
Set operations take two multisets and produce a new multiset. The types of both arguments and the result
have to match. If there are multisets of vertices or edges, the vertices or edges must come from the same
graph.
UNION ALL
Returns a multiset containing all elements from both arguments. Duplicates are not removed.
UNION
Returns all unique elements from both arguments by removing the duplicates found. UNION has the same
result as UNION ALL with a subsequent DISTINCT.
INTERSECT ALL
Returns all elements that are present in both arguments. Duplicates are not removed.
EXCEPT ALL
Returns all elements that are present in the left-hand argument but not in the right-hand argument. Duplicates
are not removed.
EXCEPT
Returns all unique elements that are present in the left-hand argument but not in the right-hand argument.
Duplicates are removed. EXCEPT has the same result as EXCEPT ALL with a subsequent DISTINCT.
6.4.2 SEQUENCE
A sequence is an ordered collection. It is possible to access and modify any element through its position, which
is between 1L and the size of the sequence.
The elements of a sequence can be of type WEIGHTEDPATH; however, this is limited to the result of
K_SHORTEST_PATHS algorithm. Currently, a sequence of WEIGHTEDPATH can only be read but not modified.
Constructors
SEQUENCE variables can be initialized with a comma-separated enumeration of elements within square
brackets.
VARCHAR b = 'blue';
SEQUENCE<VARCHAR> s1 = [ 'red', 'green', :b ];
SEQUENCE<DOUBLE> s2;
SEQUENCE<BIGINT> s3 = SEQUENCE<BIGINT>();
An empty sequence of VERTEX or EDGE type requires a graph variable for initialization.
Functions
COUNT
Returns the size of the given sequence. The result type is BIGINT.
MULTISET
Returns a multiset containing elements from the given sequence. The order of elements is lost.
Operations
Concatenation
You can construct a new sequence by concatenating two sequences or concatenating a sequence with a single
element.
Positional Access
It's possible to access and modify any element of a sequence via its position, which is between 1L and the size
of the sequence.
Reads the value at a certain index position of a specified table column. Returns NULL if the desired cell index is
larger than the row count of the table. The index is 1-based, i.e., the first element is accessed with the index
number 1L.
INTEGER i = :tab."IntColumn"[1L];
Sets the value at a certain index position of a specified table column. If the index is larger than the row count of
the table, then the table is resized accordingly and padded with NULL values if necessary.
tab."IntColumn"[5L] = 123;
Row Count
The row count of a table can be determined using the COUNT function expression.
Examples
Projection Expression
Projection expressions are special expressions that can only be used in assignment statements. They're only
allowed on the right-hand side of the assignment statement, while the left-hand side must be of type table.
The order of the projected attributes and their types must match the columns of the output parameter type.
Attribute names are ignored and the columns of the output table are named according to the output parameter
type.
Note
Examples
A table attribute can also be cast to a multiset or a sequence of scalars, provided that their element primitive
types match.
Examples
SEQUENCE<INTEGER> si = SEQUENCE<INTEGER>(:i_tab."ATTR");
MULTISET<INTEGER> mi = MULTISET<INTEGER>(:i_tab."ATTR");
The following table summarizes the supported scalar data types in GraphScript and classifies them by their
characteristics:
Each numeric type has a maximum value and a minimum value. A numeric overflow exception is thrown if a
given value is smaller than the minimum allowed value or greater than the maximum allowed value.
INTEGER
BIGINT
String Type
The NVARCHAR character string data type specifies character strings of variable length. It's used both for
storing ASCII and Unicode character strings. A string variable is default-initialized with value NULL.
Boolean Type
The BOOLEAN data type stores Boolean values, which are TRUE and FALSE. A variable of type BOOLEAN is
default-initialized with value NULL.
Datetime Type
Numeric Literals
A numeric literal is represented by a sequence of digits that are not enclosed in quotation marks. If a numeric
literal contains a decimal point, then it's treated as a DOUBLE precision floating point value. BIGINT literals
need to be suffixed with an L.
Examples
123 -- INTEGER
123L -- BIGINT
123.4 -- DOUBLE
String Literals
A character string literal is enclosed in single quotation marks. The character string literal is optionally prefixed
by an N.
<varchar_literal> ::=
<single_quote> {<any_character>-<single_quote>} <single_quote>
<nvarchar_literal> ::=
| N<single_quote > {<any_character>-<single_quote>} <single_quote>
Examples
'Material' -- VARCHAR
'23' -- VARCHAR
N'is used in ' -- NVARCHAR
Boolean Literals
A Boolean literal can be either TRUE or FALSE. Both literals are keywords in GraphScript and therefore are
case-insensitive.
Examples
TIMESTAMP('2019-12-19 16:30:12.345')
INTEGER
Casts a DOUBLE or BIGINT value to an INTEGER value. Throws a conversion error in the event of value
overflows or underflows.
DOUBLE
BIGINT
Casts an INTEGER or DOUBLE value to a BIGINT value. Throws a conversion error in the event of value
overflows or underflows.
VARCHAR
NVARCHAR
Arithmetic expressions are binary expressions that take two expressions and an arithmetic operator and
produce a result. Both expressions have to be of the same type.
Examples
INTEGER suma = 2 + 3;
BIGINT prod = 2L * 3L;
DOUBLE quot = 2.0 / 3.0;
INTEGER mod = 10 % 3;
Concatenation
String concatenation is a binary expression that takes two expressions and a concatenation operator and
produces a combined string value. Both expressions have to be of character string type.
Examples
TIMESTAMP
Creates a timestamp value from the given character string. Throws a conversion error if the character string is
not a valid timestamp value.
NANOSECOND
SECOND
MINUTE
HOUR
DAYOFMONTH
MONTH
YEAR
Relational Expressions
Relational expressions are binary expressions that compare the values produced by two expressions and return
a BOOLEAN value. Both expressions must be of the same type. For VERTEX, EDGE, and BOOLEAN types, only
equality and inequality comparisons are allowed. For membership testing, the right operand must be a
multiset. Comparisons with NULL give a false result, that is, if both compared values are NULL and the
comparison operator is equals, the result is false.
Examples
:intValue > 3
(:doubleValue - 2.0 ) < 17
:v_current == VERTEX(:g, 'ID0001')
Logical Expressions
Logical expressions take two expressions and a logical operator and produce a Boolean result value. Both
expressions have to be of the same type.
(3 == 4) AND (4 == 3)
TRUE OR (:e.WEIGHT > 3)
NOT (3 == 2)
IS NULL Expressions
The unary IS NULL and IS NOT NULL expressions allow you to check whether a scalar value or attribute have
the value NULL. The return type of the expressions is a Boolean value.
Examples
Size Limits
The following table shows the maximum allowable limit for each entry.
Description Limit
● Caching is not supported for graph workspaces that refer to virtual tables.
● The usage of cross-database access in a scenario with more than one tenant database in combination with
SAP HANA Graph is not supported.
The following example uses the Open Flights data set and computes the 3 shortest paths between Jinan and
Philadelphia.
openCypher is a declarative graph query language for graph pattern matching developed by the openCypher
Implementers Group. (Cypher is a registered trademark of Neo4j, Inc.)
SAP HANA Graph allows you to use openCypher directly in SQL and in SAP HANA Calculation Views. This
chapter describes the SQL interface and the currently supported subset of the openCypher query language.
For a detailed description of how to execute an openCypher query in SAP HANA Calculation Views, see Query
Language [page 77].
The OPENCYPHER_TABLE SQL Function enables the embedding of an openCypher query in an SQL query. The
result is returned as a table. The column names and types of this table are determined by both the openCypher
query [page 53] and the graph workspace [page 7].
OPENCYPHER_TABLE is robust with respect to inconsistent graph workspaces. Errors can occur in rare cases,
but usually the inconsistent parts do not show in the result.
Syntax
OPENCYPHER_TABLE (
<graph_workspace_spec>
<opencypher_query_spec>
)
Syntax Elements
<graph_workspace_spec>
<graph_workspace> can be any graph workspace present in the system, identified by an optional schema
name and a workspace name.
Note
Since a single-quoted SQL string is used for the openCypher query, single quotes (') inside the openCypher
query have to be escaped by using two single quotes ('').
Examples
The example is based on the Open Flights graph from section Appendix A - Open Flights Graph Example [page
79].
Name
Related Information
An openCypher query searches for subgraphs that match the specification given in MATCH clauses and
returns a result table as specified in the RETURN clause.
The total number of MATCH clauses in one openCypher is currently limited to five. OpenCypher expressions
can only include vertex or edge attributes of the following types: INT, BIGINT, DOUBLE, NVARCHAR, DATE, and
TIMESTAMP. Vertex or edge attributes of other types can be used in the RETURN-clause, but not within
aggregation functions or other expressions.
The MATCH clause consists of topological constraints that define the topology (vertices, edges, and paths) of
the matching subgraphs, and an optional filter condition, which allows the user to add additional
(nontopological) constraints. These constraints must be fulfilled by each match in the graph workspace to
become a part of the result.
Topological Constraints
Topological constraints are a comma-separated list of vertices and edges. Additionally, one path can be used.
<topology_constraint> ::=
<vertex>
| <edge>
| <path>
Edges and paths can be directed or undirected. Undirected edges and paths match edges and paths of any
direction. Specification of edges and paths requires source and target vertices.
The length of paths must be provided. The minimal and maximal length of a path must be in the range 1-15.
The following examples show the use of different topological constraints in the MATCH clause:
● One vertex
MATCH (a) RETURN a.NAME AS name
● One directed edge
MATCH (a)-[e]->(b) RETURN e.TYPE AS type
● One undirected edge
MATCH (a)-[e]-(b) RETURN e.KEY AS key
● Directed variable-length path
MATCH p=(a)-[*1..2]->(b) RETURN a.NAME AS aName, b.NAME AS bName
● Undirected variable-length path
MATCH p=(a)-[*5..7]-(b) RETURN a.NAME AS aName, b.NAME AS bName
MATCH (a)-[e]-(b)
WHERE a.NAME = 'John F Kennedy International Airport' RETURN b.NAME AS Name
ORDER BY b.NAME
Name
MATCH p = (a)-[*1..2]->(b)
WHERE a.NAME = 'Philadelphia International Airport'
RETURN b.NAME AS Name
ORDER BY b.NAME
The path with the name p starts from vertex a and ends at vertex b. It's one or two edges long. This query
returns all vertices that are related to Philadelphia International Airport by outgoing edges. The result is:
MATCH (a)-[e1]->(b)
MATCH (b)-[e2]->(c)
WHERE a.NAME = 'Philadelphia International Airport' RETURN c.NAME AS Name
ORDER BY c.NAME
This query returns all vertices laying at a distance of two hops from Philadelphia International Airport,
considering the direction of edges:
Name
Note
Note that Philadelphia International Airport is among the results, which means that edge variables e1 and
e2 match the same edge in the data graph. It is not possible if e1 and e2 are defined in the same MATCH
clause.
Non-Topological Constraints
Nontopological constraints is a Boolean expression that is evaluated on each matched subgraph. This
expression can contain many predicates that are combined by the logical connectives AND, OR, and NOT.
Predicates include comparisons (=, <>, >, <, >=, <=), IS NULL, and other Boolean built-in functions.
The following query illustrates string concatenation and the use of the logical connective NOT. Note that NOT
has higher precedence than AND and OR. Therefore, NOT is evaluated first.
MATCH (a)-[e]->(b)
WHERE a.NAME = ''John F Kennedy'' + '' International Airport''
AND (e.EDGE_KEY < 4 OR NOT b.NAME <> ''Philadelphia International Airport'')
RETURN b.NAME AS Name
ORDER BY b.NAME
The following query illustrates the use of the logical connective OR. Note that OR has lower precedence than
AND.
MATCH (a)-[e]->(b)
WHERE a.NAME = 'John F Kennedy International Airport'
AND e.EDGE_KEY > 4 OR b.NAME = 'Philadelphia International Airport'
RETURN b.NAME AS Name
ORDER BY b.NAME
The following query illustrates the use of parentheses to evaluate the OR connective before the AND
connective.
MATCH (a)-[e]->(b)
WHERE a.NAME = ''John F Kennedy International Airport''
AND (e.EDGE_KEY > 4 OR b.NAME = ''Philadelphia International Airport'')
RETURN b.NAME AS Name
ORDER BY b.NAME
Name
MATCH (a)
WHERE a.NAME CONTAINS 'International'
RETURN a.NAME AS Name
ORDER BY a.NAME
Name
The RETURN clause lists expressions over the matched subgraphs that need to be projected into the resulting
table. The optional DISTINCT specifier eliminates duplicate rows from the resulting table. The optional ORDER
BY clause allows you to sort the resulting rows in ascending or descending order. The optional LIMIT clause of
the RETURN clause truncates the resulting table to the given number of rows (from the top) if the result has
more rows than the given number. Otherwise, all the rows are displayed. The optional SKIP clause excludes the
given number of rows from the top of the result. When all three optional clauses are present, the ORDER-BY
clause is applied first, then the SKIP clause, and finally the LIMIT clause.
If there's more than one return item and at least one aggregation, the result is grouped by the not aggregated
return items. The MAX, MIN, and SUM functions need a numeric type as input and the result type corresponds
to the input type. The COUNT function can take any type as input and the result type is always BIGINT.
MATCH (a)-[e]->(b)
WHERE e.DIST_KM > 5000.0
List comprehension is useful for extracting edge attributes of a path. List comprehension constructs a new list
from the given path function, returning a list of edges and the given expression that can use the given iterator
variable. It's only permitted in the RETURN clause. The resulting column is a string representation of the list
comprehension result in JSON format. The following expressions are allowed in the list comprehension:
attribute accesses, string concatenations, and constants. The following example shows how to use the list
comprehension.
MATCH p = (a)-[*1..2]->(b)
WHERE a.NAME STARTS WITH 'Philadelphia'
RETURN [e IN RELATIONSHIPS(p) | e.TARGET] AS result
result
["JFK"]
["JFK", "FRA"]
["JFK", "AMS"]
["JFK", "DXB"]
["JFK", "DEL"]
["JFK", "PHL"]
The object constructor can group several expressions into one expression. It's only permitted in the RETURN
clause. The resulting column is a string representation of the object in JSON format. The following example
shows how to use the object constructor.
MATCH (a)-[e]->(b)
WHERE a.NAME STARTS WITH 'Dubai'
RETURN { from: e.SOURCE, to: e.TARGET } AS result
result
{"from":"DXB","to":"FRA"}
{"from":"DXB","to":"AMS"}
{"from":"DXB","to":"PEK"}
{"from":"DXB","to":"JFK"}
{"from":"DXB","to":"DEL"}
The following openCypher query returns the values of the "NAME" attribute of all vertices in the given graph.
MATCH (a)
RETURN a.NAME AS name
ORDER BY a.NAME ASC
Name
Yaoqiang Airport
The following query illustrates the use of the LIMIT clause applied to the result from the previous example:
MATCH (a)
RETURN a.NAME AS name
ORDER BY a.NAME ASC
LIMIT 5
Name
The following query illustrates the use of the SKIP clause applied to the result from the previous example:
MATCH (a)
RETURN a.NAME AS name
ORDER BY a.NAME ASC
LIMIT 5
SKIP 1
Name
Keywords
Reserved Keywords
The following query illustrates the case sensitivity of variable names (a and A are not the same).
This query also illustrates a disconnected graph pattern, since vertices a and A are not connected by any edge.
In other words, there are two connected components, each of them containing one vertex. From a performance
perspective, we recommend that you avoid matching disconnected subgraphs wherever possible, because the
result is the Cartesian product of matches of all connected components (225 rows), which can easily get large
and use up system resources.
MATCH (A)-[e]->(a)
RETURN a.NAME AS name, A.NAME as NAME
ORDER BY a.NAME ASC, A.NAME DESC
SAP HANA Graph supports a subset of openCypher built-in functions and offers a set of SAP HANA-specific
built-in functions.
openCypher built-in functions are case-insensitive. SAP HANA-specific built-in functions are defined in the SYS
namespace and are case-sensitive.
RELATIONSHIPS
The RELATIONSHIPS function takes a path variable and returns a collection of all edges in the path.
ALL
The ALL function returns a Boolean result and can be used as a predicate in a WHERE clause. This function
returns true if the given condition is true for all elements in the given collection. Otherwise, it returns false.
The following example shows how to use the ALL function. If you're only interested in Dubai's direct and
indirect ultra-long range connections, you can use an additional edge filter for all edges of a path.
MATCH p = (a)-[*1..2]->(b)
WHERE a.NAME STARTS WITH ''Dubai'' AND ALL(e IN RELATIONSHIPS(p) WHERE e.DIST_KM
> 8000.0)
RETURN DISTINCT b.NAME AS Name
ORDER BY b.NAME
Name
SYS.TEXT_CONTAINS
The function SYS.TEXT_CONTAINS makes advanced text search capabilities available in openCypher.
This function returns a Boolean result and can be used as a predicate in a WHERE clause of an openCypher
query.
The first parameter is a vertex or directed edge attribute of types VARCHAR or NVARCHAR. The second
parameter is a string literal that specifies the search pattern, and the third parameter is a string literal
specifying one of the three available search modes: EXACT, LINGUISTIC, or FUZZY. The search pattern might
contain reserved operators (-,?,",*,OR,%) that have special meaning, depending on the search mode.
MATCH (a)
WHERE SYS.TEXT_CONTAINS(a.name,'Dubbai','FUZZY(0.8)')
RETURN a.id
MATCH (a)-[e]->(b)
WHERE SYS.TEXT_CONTAINS(e.color,'b*','EXACT')
RETURN a.id
Additionally, the user can create a full-text index for any NVARCHAR column in the vertex or edge table to
transform the search into a full-text search. More information about the full-text search and how to create a
full-text index can be found in the SAP HANA Search Developer Guide and in the SAP HANA SQL Reference
Guide for SAP HANA Platform.
Exact search
In the EXACT search mode, the search term must match the entire search pattern to return a column entry as a
match. In this search mode, the user can specify the search pattern as a complex predicate using the following
specific operators. Some operators are useful only in a full-text search.
● With a minus sign (-), SAP HANA searches in columns for matches that do not contain the term
immediately following the minus sign.
Examples for complex search patterns in the EXACT search mode are:
Linguistic search
A linguistic search finds all words that have the same word stem as the search term. It also finds all words for
which the search term is the word stem. When you execute a linguistic search, the system has to determine the
stems of the searched terms. It will look up the stems in the stem dictionary. The hits in the stem dictionary
point to all words in the word dictionary that have this stem.
SYS.TEXT_CONTAINS(a.attribute,'produced','LINGUISTIC')
A linguistic search for 'produced' will also find 'producing' and 'produce'.
Fuzzy search
Fuzzy search is a fast and fault-tolerant search feature in SAP HANA. A fuzzy search returns records even if the
search term contains additional or missing characters or other types of spelling errors. The first parameter, the
fuzzy score, defines how different the search pattern can be. It is a floating-point number from 0 through 1 and
the larger the number, the less difference is allowed. Moreover, the fuzzy search mode takes many additional
parameters that define how the fuzzy score is calculated.
A fuzzy search for 'Dubai' with an appropriate fuzzy score also returns vertices containing the word 'Dubbai' or
'Dubay'. This provides the user the possibility to query dirty data, for example, querying misspelled names.
The following table shows a few additional options to influence fuzzy search results. Many options conflict with
each other or need to be combined with different options. For more detailed information about these options
and additional options, see the SAP HANA Search Developer Guide.
termMappingTable unquoted sql identifier Defines terms that are used to extend a
search to generate additional results
Basic Rules
<backtick> ::= `
<dot> ::= .
<double_dot> ::= ..
<comma> ::= ,
<minus> ::= -
<l_paren> ::= (
<r_paren> ::= )
<l_curly> ::= {
<r_curly> ::= }
<l_square> ::= [
<r_square> ::= ]
<greater> ::= >
<equal> ::= =
<lower> ::= <
<lower_equal> ::= <=
<greater> ::= >
<greater_equal> ::= >=
<unequal> ::= <>
<asterisk> ::= *
<single_quote> ::= '
<double_quote> ::= "
SAP HANA Graph provides a graph calculation node that can be used in calculation scenarios.
This node allows you to execute one of the available actions on the given graph workspace and provide results
as table output.
Calculation scenarios can be created with plain SQL as shown in the following section or with tools such as the
SAP HANA Modeler (see SAP HANA Modeling Guide) or a native SAP HANA Graph Viewer (see Appendix D -
SAP HANA Graph Viewer [page 91]).
Parameter Value
In case of an inconsistent graph workspace, the calculation scenario will exit with an error.
To use the graph node, a user needs SELECT privileges on the given graph workspace.
Each action has a set of additional parameters. The remainder of this section describes the available actions
and their additional parameters.
Related Information
SAP HANA Modeling Guide for SAP Web IDE for SAP HANA
SAP HANA Modeling Guide for SAP HANA Web Workbench
SAP HANA Modeling Guide for HANA Studio
The GET_NEIGHBORHOOD graph action retrieves the neighboring vertices within the given radius (depth) from
the given start vertices.
This action allows you to specify multiple start vertices, choose traversal direction, setting filters on vertices
and edges, and setting minimum and maximum depth (radius) of the neighborhood.
Parameter Value
direction Traversal direction, can use one of the following values: any,
incoming, outgoing
Parameter Value
vertex table Contains the set of explored vertices with vertex key and the
depth level of the neighborhood.
The SQL statement used in the following code sample creates a calculation scenario with a single graph node
with the GET_NEIGHBORHOOD action on the graph workspace "FLIGHTS"."GRAPH". This scenario traverses
the underlying graph using all outgoing edges starting from vertex 'AMS' and returns vertices with minimum
depth 0 and maximum depth 2 from the start vertex.
NODE_KEY DEPTH
AMS 0
JFK 1
DXB 1
FRA 1
PEK 1
DEL 1
PHL 2
TNA 2
The same result can be obtained through the SAP HANA Graph Viewer web tool (see Appendix D - SAP HANA
Graph Viewer [page 91]).
The following SQL statement deletes the calculation scenario and its corresponding view:
Note
The SAP HANA Graph Viewer can be used to create the calculation scenario, execute the neighborhood
search on the selected graph workspace with specific parameters and to visualize the result. Afterwards
the generated calculation scenario can be reused in all kinds of SQL queries.
The action GET_SHORTEST_PATHS_ONE_TO_ALL returns the shortest paths from the provided start vertex to
all reachable vertices in the graph - also known as single-source shortest path (SSSP). The resulting shortest
paths form a tree structure with the start vertex at the root. All other vertices carry the shortest distance
(smallest weight) information. The non-negative edge weights are read from the column provided in the edge
table.
Parameter Value
The SQL statement used in the following code sample creates a calculation scenario with a single graph node
with the action GET_SHORTEST_PATHS_ONE_TO_ALL on the workspace "FLIGHTS"."GRAPH". This scenario
calculates shortest paths from the vertex 'FRA' to all other vertices. Since input weight column parameter is not
specified, the weight of each edge is considered as 1.
The following SQL statement executes the calculation scenario and sorts the result by the output weight
column "DISTANCE".
The result of this operation is the vertex table with an additional column for shortest distance:
NODE_KEY DISTANCE
FRA 0
DEL 1
JFK 1
PEK 1
AMS 1
DXB 1
TNA 2
PHL 2
Note
The same results can also be obtained by executing GET_NEIGHBORHOOD action with startVertices equal
to 'FRA', direction equal to 'outgoing', minDepth equal to '0', maxDepth equal to '*', and depthColumn equal
to 'DISTANCE'.
The following SQL statement drops the calculation scenario and all its views.
The following statement creates a calculation scenario that returns both vertices and edges of shortest paths
from the start vertex 'FRA' to all other vertices in the graph workspace "FLIGHTS"."GRAPH".
The following SQL statement executes the calculation scenario and returns edges of all shortest paths ordered
by edge keys.
The result of this operation is the edge table containing edge keys, source vertex keys and target vertex keys:
1 FRA PEK
7 FRA JFK
12 FRA AMS
13 FRA DXB
14 FRA DEL
30 JFK PHL
31 PEK TNA
The following SQL statement drops the calculation scenario and all its views.
Note
The SAP HANA Graph Viewer can be used to create the calculation scenario, execute the shortest path
algorithm on the selected graph workspace with specific parameters and to visualize the result. Afterwards
the generated calculation scenario can be reused in all kinds of SQL queries.
The action GET_SHORTEST_PATH_ONE_TO_ONE returns the shortest path from the provided start vertex to the
provided target vertex - also known as single-source single-target shortest path (SSSTSP).
The resulting table contains all vertices of the shortest path between the start vertex and the target vertex with
the distance from the start vertex.
If there is more than one shortest path between the two vertices, only one of them is returned.
The non-negative edge weights are read from the column provided in the edge table.
Examples
The following SQL statement executes the calculation scenario and sorts the result by the column
"ORDERING":
1 FRA JFK 1
2 JFK PHL 2
A directed graph is said to be strongly connected if every vertex is reachable from every other vertex. The
strongly connected components of an arbitrary directed graph form a partition into subgraphs that are
themselves strongly connected.
The only output of this action is a table containing the vertex key column and a "COMPONENT" column
containing strongly connected component indices. All vertices with the same component index belong to the
same strongly connected component.
Parameter Value
Parameter Value
vertex table Contains vertex key column and component index column
The SQL statement used in the following code sample creates a calculation scenario with a single graph node
with the GET_STRONGLY_CONNECTED_COMPONENTS action on the graph workspace "FLIGHTS"."GRAPH".
The following SQL statement executes the calculation scenario and sorts the result by the component index.
TNA 1
PHL 2
DEL 2
JFK 2
DXB 2
AMS 2
PEK 2
FRA 2
The same result can be obtained through the SAP HANA Graph Viewer web tool (see Appendix D - SAP HANA
Graph Viewer [page 91]).
The following SQL statement deletes the calculation scenario and its corresponding view.
Graph variables allow to parameterize calculation scenarios, so that the same graph action can be called with
different parameters.
Using the graph variables, a user needs to create only one calculation scenario for a combination of the graph
workspace and the graph action.
The following SQL statement illustrates a parameterized calculation scenario for the GET_NEIGHBORHOOD
graph action and the "FLIGHTS"."GRAPH" graph workspace that uses graph variables.
The graph variables $$direction$$, $$minDepth$$, $$vertexFilter$$ and $$edgeFilter$$ all have
defined default values and therefore can be omitted when executing the calculation scenario.
Note
The SAP HANA Graph Viewer can be used to create the calculation scenario, execute the strongly
connected component algorithm on the selected graph workspace with specific parameters, and visualize
the result. Afterwards the generated calculation scenario can be reused in all kinds of SQL queries.
Pattern matching is a kind of graph query, which involves finding all the subgraphs (within a graph) that match
the given pattern.
SAP HANA Graph provides two options for executing graph pattern queries. The first option is to use the
graphical pattern editor in SAP Web IDE for SAP HANA. The second option is to describe the pattern in
openCypher query language.
The action MATCH_SUBGRAPHS allows you to execute pattern matching queries written in the supported subset
of the openCypher Query Language [page 53] on the given graph workspace.
Note
openCypher queries provide different results than graphical pattern matching. In graphical pattern
matching, the uniqueness of edges and vertices is enforced. In contrast, the semantic of an openCypher
query only enforces the uniqueness of edges.
The SQL statement used in the following code sample creates a calculation scenario with a single graph node
with the MATCH_SUBGRAPHS action on the graph workspace "FLIGHTS"."GRAPH". The openCypher query
searches for connections been FRA and DEL with exactly one intermediate landing. Note that single quotes
inside the query need to be properly escaped when creating a calculation scenario.
Related Information
Use the following SQL statements to create the Open Flights graph example.
The syntactic notation used in this guide is an extended version of BNF ("Backus Naur Form").
In a BNF language definition, each syntactic element of the language (known as a BNF nonterminal symbol) is
defined by means of a production rule. This rule defines the element in terms of a formula consisting of the
characters, character strings, and syntactic elements that can be used to form an instance of the formula.
The following table explains the symbols used and their meanings:
Symbol Meaning
<> A character string enclosed in angle brackets is the name of a syntactic element (BNF nontermi
nal) of the GraphScript language.
::= The definition operator is used in a production rule to separate the element defined by the rule
from its definition. The element being defined appears to the left of the operator and the formula
that defines the element appears to the right.
[] Square brackets indicate optional elements in a formula. The portion of the formula within the
brackets can be explicitly specified or can be omitted.
{} Braces group elements in a formula. Curly braces indicate that the expression can be repeated
zero or more times.
| The alternative operator. The vertical bar indicates that the portion of the formula following the bar
is an alternative to the portion preceding the bar. If the vertical bar appears at a position where it is
not enclosed in braces or square brackets, it specifies a complete alternative for the element de
fined by the production rule. If the vertical bar appears in a portion of a formula enclosed in braces
or square brackets, it specifies alternatives for the contents of the innermost pair of these braces
or brackets.
!! Introduces normal English text. This is used when the definition of a syntactic element is not ex
pressed in BNF.
- The minus operator. The horizontal bar excludes the result of the formula following the bar from
valid rules that are defined in front of the bar. The scope of this operator is equivalent to the scope
of the alternative operator.
Spaces are used to separate syntactic elements. Multiple spaces and line breaks are treated as a single space.
Apart from those symbols with special functions (see previous table), other characters and character strings in
a formula stand for themselves. In addition, if the symbols to the right of the definition operator in a production
consist entirely of BNF symbols, then these symbols stand for themselves and do not take on their special
meaning.
Pairs of braces and square brackets can be nested to any depth, and the alternative operator can appear at any
depth within such a nest.
A character string, which forms an instance of any syntactic element, can be generated from the BNF definition
of that syntactic element by performing the following steps:
● Select any one option from those defined in the right-hand side of a production rule for the element and
replace the element with this option.
● Replace each ellipsis, and the object it applies to, with one or more instances of that object.
● For every portion of the string enclosed in square brackets, either delete the brackets and their contents or
change the brackets to braces.
● For every portion of the string enclosed in braces, apply steps 1 through 5 to the substring between the
braces, then remove the braces.
● Apply steps 1 through 5 to any BNF nonterminal symbol that remains in the string.
The expansion or production is complete when no further nonterminal symbols remain in the character string.
By applying the previous steps 1 through 5 to NT, and always selecting the leftmost BNF nonterminal in step 5,
the left normal form derivation of a character string CS in the source language character set from a BNF
nonterminal NT is obtained.
GraphScript is the imperative extension language of SAP HANA Graph. It's designed to ease the development
of application-specific graph algorithms and to integrate them into the overall data processing workflow.
General Structure
INTEGER i = 23;
i = INTEGER(45L); -- cast BigInt to Integer
i = INTEGER(23.5); -- cast Double to Integer
BIGINT b = 23L;
b = BIGINT(45); -- cast Integer to BigInt
DOUBLE d = 23.5;
d = DOUBLE(12L); -- cast BigInt to Double
String Type
NVARCHAR v = 'Test';
Boolean Type
BOOLEAN b = TRUE;
Defines a boolean variable with initial value TRUE. The default value is FALSE.
Timestamp
TIMESTAMP t = TIMESTAMP(
Graph Types
GRAPH g1 = GRAPH("my_graph_workspace");
GRAPH g2 = GRAPH("my_schema", "workspace");
Constructs vertex and edge references from a graph variable and a primary key, which can consist of multiple
components.
Variables
Variable names are case-insensitive and unique within a block scope and all its subscopes.
INTEGER a = 23;
INTEGER b = 0;
b = :a;
In contrast to write access, read access to a local variable has to be prefixed by a colon.
FOREACH Loop
INTEGER i = 0;
WHILE (:i < 10) {
i = :i + 1;
}
Conditional Statements
IF (2 < 3) {
IF (TRUE) {
} ELSE {
}
}
Comments
Attribute Access
INTEGER a = :v.attr;
v.attr = 23;
Relational Expression
2 < 3
3 == 4
:a.weight >= 5
:v.attr != 'blue'
Arithmetic Expression
2 + 3
3 - 1
Logical Expressions
(3 == 4) AND (4 == 3)
TRUE OR (:a.weight > 3)
NOT (3 == 2)
(:a.attr IS NULL) AND (:b.attr IS NOT NULL)
Membership Expression
:i IN :mset_int
:str NOT IN :mset_nvarchar
Existence Expression
VERTEX_EXISTS(:g, 'keyVal')
Filter Expression
Projection Expression
Temporary Attributes
Constructors
MULTISET<VERTEX> m1 = MULTISET<VERTEX>(:g);
MULTISET<INTEGER> m3;
MULTISET<INTEGER> m4 = MULTISET<INTEGER>(:seq_int);
Operations
DISTINCT(:m1)
:m1 INTERSECT [ALL] :m2
:m1 UNION [ALL] :m2
:m1 EXCEPT [ALL] :m2
BIGINT sz = COUNT(:m1);
Sequences
Constructors
SEQUENCE<VERTEX> s1 = SEQUENCE<VERTEX>(:g);
SEQUENCE<INTEGER> si = SEQUENCE<INTEGER>(
:tab."colInt");
Operations
Tables
Operations
Graph Algorithms
IS_REACHABLE
VERTICES / EDGES
MULTISET<VERTEX> vs = VERTICES(:g);
SEQUENCE<VERTEX> sv = VERTICES(:path);
MULTISET<EDGE> me = EDGES(:g);
MULTISET<EDGE> es = EDGES(:g, :vsSrc, :vsTgt);
MULTISET<EDGE> mi = IN_EDGES(:v);
MULTISET<EDGE> mo = OUT_EDGES(:v);
SOURCE / TARGET
VERTEX v = SOURCE(:e);
VERTEX v = TARGET(:e);
SUBGRAPH
INVERSEGRAPH
GRAPH g1 = INVERSEGRAPH(:g);
SHORTEST_PATH
WEIGHTEDPATH<BIGINT> p1
= SHORTEST_PATH(:g, :v1, :v2);
WEIGHTEDPATH<INTEGER> p2
= SHORTEST_PATH(:g, :v1, :v2,
(EDGE e) => INTEGER { return :e.attr; });
Determines the shortest path between two vertices based either on hop distance or on a custom weight
function.
WEIGHTEDPATH<BIGINT> p3
= SHORTEST_PATH(:g, :v1, :v2, 'ANY');
Determines the shortest path between two vertices irrespective of the connecting edges' direction.
K_SHORTEST_PATHS
SEQUENCE<WEIGHTEDPATH<BIGINT>> paths
= K_SHORTEST_PATHS(:g, :v1, :v2, :k);
SEQUENCE<WEIGHTEDPATH<INTEGER>> paths2
= K_SHORTEST_PATHS(:g, :v1, :v2, :k,
(EDGE e) => INTEGER { return :e.attr; });
Determines the top k shortest paths between two vertices either based on hop distance or on a custom weight
function.
SHORTEST_PATHS_ONE_TO_ALL
GRAPH g2 = SHORTEST_PATHS_ONE_TO_ALL (
:g, :startVertex, "WEIGHT",
(EDGE e) => DOUBLE { RETURN :e.len; },
'INCOMING'
);
Determines the shortest paths between a start vertex and all other reachable vertices within a given graph
traversing the connecting edges in reverse direction.
STRONGLY_CONNECTED_COMPONENTS
MULTISET<MULTISET<VERTEX>> mmv;
mmv = STRONGLY_CONNECTED_COMPONENTS(:g);
WEIGHT
LENGTH
Datetime Functions
Traversal Hooks
Breadth-first traversal with vertex and edge hooks and traversal depth.
The Graph Viewer is a native SAP HANA application that provides an interface to interact with and visualize
graph workspaces in SAP HANA.
SAP HANA Graph Viewer is an additional tool for SAP HANA Graph that can be downloaded from the SAP
Software Downloads.
For more information, see SAP Note 2306732 - SAP HANA Graph Viewer and Deploy a Delivery Unit Archive
(*.tgz) in the SAP HANA Administration Guide.
Note
After the installation, the SAP HANA Graph Viewer can be accessed via the URL http://
<WebServerHost>:80<SAPHANAinstance>/sap/hana/graph/viewer/
The SAP HANA Graph Viewer supports the following Web browsers: Chrome and Mozilla Firefox.
Related Information
For information about the capabilities available for your license and installation scenario, refer to the Feature
Scope Description for SAP HANA.
Hyperlinks
Some links are classified by an icon and/or a mouseover text. These links provide additional information.
About the icons:
● Links with the icon : You are entering a Web site that is not hosted by SAP. By using such links, you agree (unless expressly stated otherwise in your
agreements with SAP) to this:
● The content of the linked-to site is not SAP documentation. You may not infer any product claims against SAP based on this information.
● SAP does not agree or disagree with the content on the linked-to site, nor does SAP warrant the availability and correctness. SAP shall not be liable for any
damages caused by the use of such content unless damages have been caused by SAP's gross negligence or willful misconduct.
● Links with the icon : You are leaving the documentation for that particular SAP product or service and are entering a SAP-hosted Web site. By using such
links, you agree that (unless expressly stated otherwise in your agreements with SAP) you may not infer any product claims against SAP based on this
information.
Example Code
Any software coding and/or code snippets are examples. They are not for productive use. The example code is only intended to better explain and visualize the syntax
and phrasing rules. SAP does not warrant the correctness and completeness of the example code. SAP shall not be liable for errors or damages caused by the use of
example code unless damages have been caused by SAP's gross negligence or willful misconduct.
Bias-Free Language
SAP supports a culture of diversity and inclusion. Whenever possible, we use unbiased language in our documentation to refer to people of all cultures, ethnicities,
genders, and abilities.
SAP and other SAP products and services mentioned herein as well as
their respective logos are trademarks or registered trademarks of SAP
SE (or an SAP affiliate company) in Germany and other countries. All
other product and service names mentioned are the trademarks of their
respective companies.