# RETURN {bdg-primary-line}`GQL clause` Ends a query and names the columns of its result. ## Synopsis
RETURN [ DISTINCT | ALL ] { * | expression [ AS alias ] } [, ...]

bold keywords · italic placeholders you supply · [ ] optional · ... repeatable. See Syntax conventions.

## Description `RETURN` is the terminal projection. It evaluates its expressions once per working row and emits them as the query's result columns. A read query must end with `RETURN` or [`FINISH`](finish.md); a write query may end with either of those or with the write clause itself. - **A property-derived column comes back as jsonb.** `RETURN m.title` prints `"The Matrix"`, with the quotes, and so does `RETURN m.title::text`. To get a plain scalar, wrap the query in SQL. See [Notes](#notes). - `*` projects every **named** binding in scope. Pattern elements you left unnamed are not projected. - An **aggregate** in the list groups implicitly: the non-aggregated expressions become the grouping key, as they would in SQL with a `GROUP BY`. - `DISTINCT` removes duplicate result rows. `ALL` is the explicit spelling of the default and keeps them. - `ORDER BY`, `SKIP`/`OFFSET` and `LIMIT` are **separate clauses** that follow a `RETURN`, not parts of it. They have their own pages, [`ORDER BY`](order-by.md) and [`SKIP` and `LIMIT`](skip-and-limit.md). - Unlike [`WITH`](with.md), `RETURN` allows the same output name twice, because nothing downstream has to resolve it. ## Parameters DISTINCT : Removes duplicate rows from the result. ALL : Keeps duplicate rows. This is the default. \* : Projects every named binding currently in scope. expression : Any Cypher expression over the bindings in scope. That includes a vertex or edge variable, a property reference, a path variable, a function call, an aggregate, an arithmetic or `CASE` expression, a list or map constructor, and a constant. alias : The result column's name. Without double quotes it folds to lower case; quote it to keep the case you wrote. With no alias, a property reference takes the property's name and anything else becomes `?column?`. ## Examples Every example runs against [the example dataset](../../get_started/example-dataset.md). ### Return a whole vertex ```cypher MATCH (p:person {name: 'Keanu Reeves'}) RETURN p; ``` ``` p --------------------------------------------------- person[4.1]{"born": 1964, "name": "Keanu Reeves"} (1 row) ``` A vertex prints as `label[id]{properties}`. An edge adds its endpoints: ```cypher MATCH (:person {name: 'Keanu Reeves'})-[r:acted_in]->(:movie {title: 'The Matrix'}) RETURN r; ``` ``` r --------------------------------------- acted_in[5.1][4.1,3.1]{"role": "Neo"} (1 row) ``` ### Return properties, with and without an alias ```cypher MATCH (p:person {name: 'Keanu Reeves'}) RETURN p.born; ``` ``` born ------ 1964 (1 row) ``` An unaliased property reference takes the property's name; a computed expression has no name to take: ```cypher MATCH (p:person {name: 'Keanu Reeves'}) RETURN p.born + 1; ``` ``` ?column? ---------- 1965 (1 row) ``` An unquoted alias folds to lower case, a quoted one does not: ```cypher MATCH (p:person {name: 'Keanu Reeves'}) RETURN p.born AS BornIn; ``` ``` bornin -------- 1964 (1 row) ``` ```cypher MATCH (p:person {name: 'Keanu Reeves'}) RETURN p.born AS "BornIn"; ``` ``` BornIn -------- 1964 (1 row) ``` ### Return everything that has a name ```cypher MATCH (p:person {name: 'Ryan Gosling'})-[r:acted_in]->(m:movie) RETURN *; ``` ``` p | r | m ----------------------------------------------------+---------------------------------------+---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- person[4.10]{"born": 1980, "name": "Ryan Gosling"} | acted_in[5.13][4.10,3.9]{"role": "K"} | movie[3.9]{"plot": "A new blade runner unearths a long-buried secret that has the potential to plunge what's left of society into chaos.", "year": 2017, "genre": "Sci-Fi", "title": "Blade Runner 2049", "embedding": [0.21560573, -0.07505179, -0.01331814, 0.13403069]} (1 row) ``` Three columns, one per named element. Had the pattern been written `(p:person {name: 'Ryan Gosling'})-[:acted_in]->(m:movie)`, `RETURN *` would give two. ### Remove duplicate rows Twenty-five `acted_in` edges point at films of three genres: ```cypher MATCH (p:person)-[:acted_in]->(m:movie) RETURN DISTINCT m.genre AS genre ORDER BY genre; ``` ``` genre ------------- "Action" "Adventure" "Sci-Fi" (3 rows) ``` Without `DISTINCT` the same query returns 25 rows. `ALL` is the explicit form of that default. ### Aggregate An aggregate with no other expression collapses the whole input to one row: ```cypher MATCH (m:movie) RETURN count(*) AS films, min(m.year) AS earliest, max(m.year) AS latest; ``` ``` films | earliest | latest -------+----------+-------- 18 | 1982 | 2021 (1 row) ``` List any other expression alongside it and that expression becomes the grouping key: ```cypher MATCH (p:person)-[:acted_in]->(m:movie) RETURN m.genre AS genre, count(*) AS roles ORDER BY genre; ``` ``` genre | roles -------------+------- "Action" | 13 "Adventure" | 1 "Sci-Fi" | 11 (3 rows) ``` `collect()` gathers a group into a list: ```cypher MATCH (p:person)-[:acted_in]->(m:movie {title: 'The Matrix'}) RETURN collect(p.name) AS cast; ``` ``` cast ------------------------------------------------------------ ["Keanu Reeves", "Laurence Fishburne", "Carrie-Anne Moss"] (1 row) ``` ### Return a constant `RETURN` needs no pattern in front of it: ```cypher RETURN 1 + 2 AS sum, 'Hello' AS greeting; ``` ``` sum | greeting -----+---------- 3 | "Hello" (1 row) ``` ## Notes Because a property-derived column comes back as jsonb, a `RETURN` is a poor interface for an application that wants native types. Put the Cypher in a `SELECT` subquery and unbox there. The jsonb operators do it: `->>` reads a key as text, and `#>> '{}'` extracts a jsonb scalar column as text. ```psql SELECT d.props ->> 'title' AS film, r.score FROM (MATCH (p:person)-[:directed]->(m:movie) WHERE p.name = 'Christopher Nolan' RETURN properties(m) AS props) d JOIN rating r ON r.title = d.props ->> 'title' WHERE r.source = 'critics' ORDER BY r.score DESC; ``` ``` film | score --------------+------- Inception | 8.8 Interstellar | 8.7 (2 rows) ``` The film titles are unquoted text here, and `score` is the table's own numeric. [Combining SQL and Cypher](../../querying/combining-sql-and-cypher.md) covers the pattern in full. ## Compatibility ### Column types ISO/IEC 39075 §14.11 `` gives a result column the declared type of its expression. AgensGraph returns every Cypher result column as jsonb regardless of the expression's type, including after an explicit cast. Unbox in SQL, as above. ### DISTINCT and ORDER BY An `ORDER BY` after `RETURN DISTINCT` may only sort by expressions that appear in the projection: ```cypher MATCH (m:movie) RETURN DISTINCT m.genre AS genre ORDER BY m.year; ``` ``` ERROR: for SELECT DISTINCT, ORDER BY expressions must appear in select list ``` This matches SQL's rule for `SELECT DISTINCT`. Project the sort key, or drop `DISTINCT` and deduplicate with a grouping aggregate instead. ## See also - [`WITH`](with.md) — the same projection, in the middle of a pipeline - [`ORDER BY`](order-by.md), [`SKIP` and `LIMIT`](skip-and-limit.md) — the clauses that follow a `RETURN` - [`FINISH`](finish.md) — end a query without returning rows - [`UNION`](union.md) — combine the results of several queries - [Combining SQL and Cypher](../../querying/combining-sql-and-cypher.md) — getting native types out