通常情况下,聚合函数aggr(expr)
会处理每个聚合键在传入记录中找到的所有匹配行(键使用等价性进行比较)。在常规聚合(即形式为aggr(expr)
的聚合)中,聚合值列表是候选值列表,并且已从中移除了所有空值。
数据准备
SELECT * FROM cypher('graph_name', $$
CREATE (a:Person {name: 'A', age: 13}),
(b:Person {name: 'B', age: 33, eyes: "blue"}),
(c:Person {name: 'C', age: 44, eyes: "blue"}),
(d1:Person {name: 'D', eyes: "brown"}),
(d2:Person {name: 'D'}),
(a)-[:KNOWS]->(b),
(a)-[:KNOWS]->(c),
(a)-[:KNOWS]->(d1),
(b)-[:KNOWS]->(d2),
(c)-[:KNOWS]->(d2)
$$) as (a agtype);
自动分组
为了计算聚合数据,Cypher提供聚合功能,类似于SQL的GROUP BY
。
聚合函数接收一组值,并计算这些值的聚合结果。例如,avg函数用于计算多个数值的平均值,min函数用于查找一组值中数值或字符串的最小值。当我们说聚合函数作用于一组值时,指的是这些值是内部表达式(如n.age
)应用于同一聚合组内所有记录的结果。
聚合可以在所有匹配的子图上进行计算,也可以通过引入分组键进一步细分。分组键是非聚合表达式,用于对进入聚合函数的值进行分组。
假设存在以下返回语句:
SELECT * FROM cypher('graph_name', $$
MATCH (v:Person)
RETURN v.name, count(*)
$$) as (grouping_key agtype, count agtype);
返回结果如下:
grouping_key | count
--------------+-------
"A" | 1
"D" | 2
"Joan" | 1
"B" | 1
"John" | 1
"Bill" | 1
"C" | 1
"Jeff" | 1
(8 rows)
返回中包含两列:grouping_key
和count(*)
。其中,grouping_key
不是聚合函数,因此它将作为分组键。count(*)
是一个聚合表达式。匹配的子图将根据分组键被划分成不同的桶。然后,聚合函数将在这些桶上运行,计算每个桶的聚合值。
使用聚合函数排序
使用聚合对结果集进行排序时,该聚合必须包含在RETURN
子句中,以便能够在ORDER BY
中使用。
SELECT *
FROM cypher('graph_name', $$
MATCH (me:Person)-[]->(friend:Person)
RETURN count(friend), me
ORDER BY count(friend)
$$) as (friends agtype, me agtype);
DISTINCT聚合
在DISTINCT聚合(即形式为aggr(DISTINCT expr)
的聚合)中,聚合值列表是从候选值列表中移除所有空值后的结果。此外,在DISTINCT聚合中,仅包含一个等价候选值,即在聚合值列表中会去除重复的等价值。
DISTINCT
操作符与聚合函数配合使用,用于在将值传递给聚合函数之前,使所有值唯一化。
示例
SELECT *
FROM cypher('graph_name', $$
MATCH (v:Person)
RETURN count(DISTINCT v.eyes), count(v.eyes)
$$) as (distinct_eyes agtype, eyes agtype);
返回结果如下:
distinct_eyes | eyes
---------------+------
2 | 3
(1 row)
模糊分组语句
此功能不需要在查询中明确指定分组键,但可能导致Cypher在确定哪些字段应该作为分组键时产生歧义。更多详细信息,请参考社区文档。
数据准备
SELECT * FROM cypher('graph_name', $$
CREATE (:L {a: 1, b: 2, c: 3}),
(:L {a: 2, b: 3, c: 1}),
(:L {a: 3, b: 1, c: 2})
$$) as (a agtype);
AGE中的无效查询
AGE对于这个问题的解决方案是不允许在WITH或RETURN子句中将聚合函数与未在相同WITH或RETURN子句的其他列中显式列出的变量组合使用。
示例
SELECT * FROM cypher('graph_name', $$
MATCH (x:L)
RETURN x.a + count(*) + x.b + count(*) + x.c
$$) as (a agtype);
返回结果如下:
ERROR: "x" must be either part of an explicitly listed key or used inside an aggregate function
LINE 3: RETURN x.a + count(*) + x.b + count(*) + x.c
AGE中的有效查询
在AGE中,不包含聚合函数的列被视为该WITH
或RETURN
子句的分组键。
示例
对于上述查询可以使用以下方式重写查询,使其正常返回结果。
-
SELECT * FROM cypher('graph_name', $$ MATCH (x:L) RETURN (x.a + x.b + x.c) + count(*) + count(*), x.a + x.b + x.c $$) as (count agtype, key agtype);
其中,
x.a + x.b + x.c
是分组键。此类创建的分组键必须包含括号。count | key -------+----- 12 | 6 (1 row)
-
SELECT * FROM cypher('graph_name', $$ MATCH (x:L) RETURN x.a + count(*) + x.b + count(*) + x.c, x.a, x.b, x.c $$) as (count agtype, a agtype, b agtype, c agtype);
其中,
x.a
、x.b
和x.c
将被视为不同的分组键。count | a | b | c -------+---+---+--- 8 | 3 | 1 | 2 8 | 2 | 3 | 1 8 | 1 | 2 | 3 (3 rows)
模糊分组中的顶点和边
分组键可以是一个顶点或边,然后可以无需在WITH或 RETURN子句中显式指定该顶点或边的任何属性。
示例
SELECT * FROM cypher('graph_name', $$
MATCH (x:L)
RETURN count(*) + count(*) + x.a + x.b + x.c, x
$$) as (count agtype, key agtype);
结果将按x
分组,因为可以合理假设属性被认为是不必要的,以确保明确分组。
count | key
-------+----------------------------------------------------------------------------------------
8 | {"id": 1407374883553283, "label": "L", "properties": {"a": 3, "b": 1, "c": 2}}::vertex
8 | {"id": 1407374883553281, "label": "L", "properties": {"a": 1, "b": 2, "c": 3}}::vertex
8 | {"id": 1407374883553282, "label": "L", "properties": {"a": 2, "b": 3, "c": 1}}::vertex
(3 rows)
隐藏不必要的分组键
如果分组键在查询输出中被认为是不必要的,可以在WITH
子句中进行聚合,然后将信息传递给RETURN
子句。
示例
SELECT * FROM cypher('graph_name', $$
MATCH (x:L)
WITH count(*) + count(*) + x.a + x.b + x.c as column, x
RETURN column
$$) as (a agtype);
返回结果如下:
a
---
8
8
8
(3 rows)
- 本页导读 (1)
- 数据准备
- 自动分组
- 使用聚合函数排序
- DISTINCT聚合
- 模糊分组语句
- 数据准备
- AGE中的无效查询
- AGE中的有效查询
- 模糊分组中的顶点和边
- 隐藏不必要的分组键