COUNT 子查询
COUNT 子查询可用于计算子查询返回的行数。
示例图
以下图表用于下方的示例
要重新创建该图,请在空的 Neo4j 数据库中运行以下查询
CREATE
(andy:Swedish:Person {name: 'Andy', age: 36}),
(timothy:Person {name: 'Timothy', nickname: 'Tim', age: 25}),
(peter:Person {name: 'Peter', nickname: 'Pete', age: 35}),
(andy)-[:HAS_DOG {since: 2016}]->(:Dog {name:'Andy'}),
(timothy)-[:HAS_CAT {since: 2019}]->(:Cat {name:'Mittens'}),
(fido:Dog {name:'Fido'})<-[:HAS_DOG {since: 2010}]-(peter)-[:HAS_DOG {since: 2018}]->(:Dog {name:'Ozzy'}),
(fido)-[:HAS_TOY]->(:Toy{name:'Banana'})
简单的 COUNT 子查询
外部作用域引入的变量可以在 COUNT 子查询中直接使用,无需导入。在这方面,COUNT 子查询不同于 需要导入变量的 CALL 子查询。以下查询展示了这一点,并输出了拥有多于一只狗的主人:
MATCH (person:Person)
WHERE COUNT { (person)-[:HAS_DOG]->(:Dog) } > 1
RETURN person.name AS name
| 名称 (name) |
|---|
|
行:1 |
带 WHERE 子句的 COUNT 子查询
WHERE 子句可以在 COUNT 模式内使用。MATCH 子句和外部作用域引入的变量均可在此作用域内使用。
MATCH (person:Person)
WHERE COUNT {
(person)-[:HAS_DOG]->(dog:Dog)
WHERE person.name = dog.name
} = 1
RETURN person.name AS name
| 名称 (name) |
|---|
|
行:1 |
条件 COUNT 子查询仅限 Cypher 25Neo4j 2025.06 引入
可以在 COUNT 子查询中使用 WHEN,以便在谓词计算结果为 true 时有条件地执行分支。请注意,不同 WHEN 分支返回的列名和列数必须完全一致。有关更多信息,请参阅 条件查询 → 条件子查询。
在下面的示例中,如果某人没有猫(c IS NULL),则执行 WHEN 分支以统计他们的狗的数量。ELSE 分支则针对那些拥有猫的人运行。
COUNT 子查询MATCH (p:Person)
OPTIONAL MATCH (p)-[:HAS_CAT]->(c)
RETURN p.name AS person, c IS NOT NULL AS hasCat,
COUNT {
WHEN c IS NULL THEN {
MATCH (p)-[:HAS_DOG]->(dog)
RETURN dog.name AS petOwner
}
ELSE {
MATCH (p)-[:HAS_CAT]->(cat)
RETURN cat.name AS petOwner
}
} AS howManyPets
| 名称 (name) | 有猫 | 宠物数量 |
|---|---|---|
|
|
|
|
|
|
|
|
|
行:3 |
||
带 UNION 的 COUNT 子查询
COUNT 可以与 UNION 子句一起使用。如果 UNION 子句是去重的(distinct),则必须包含 RETURN 子句。UNION ALL 子句则不需要 RETURN 子句。但值得注意的是,如果其中一个分支包含 RETURN 子句,那么所有分支都必须包含它。下面的示例展示了通过使用 UNION 子句统计每个人拥有的宠物数量:
MATCH (person:Person)
RETURN
person.name AS name,
COUNT {
MATCH (person)-[:HAS_DOG]->(dog:Dog)
RETURN dog.name AS petName
UNION
MATCH (person)-[:HAS_CAT]->(cat:Cat)
RETURN cat.name AS petName
} AS numPets
| 名称 (name) | 宠物数量 |
|---|---|
|
|
|
|
|
|
行:3 |
|
带 WITH 的 COUNT 子查询
外部作用域的变量在整个子查询中均可见,即使在使用 WITH 子句时也是如此。为避免混淆,不允许对这些变量进行遮蔽(shadowing)。当内部作用域中定义的变量与外部作用域变量同名时,就会发生变量遮蔽。在下面的示例中,外部变量 name 被遮蔽,因此会抛出错误。
WITH 'Peter' as name
MATCH (person:Person {name: name})
WHERE COUNT {
WITH "Ozzy" AS name
MATCH (person)-[:HAS_DOG]->(d:Dog)
WHERE d.name = name
} = 1
RETURN person.name AS name
42N07: 错误: 语法错误或访问规则冲突 - 变量遮蔽。变量 42001:错误:语法错误或访问规则冲突 - 无效语法 |
只要使用不同的标识符,就可以在子查询中引入新变量。在下面的示例中,WITH 子句引入了一个新变量。请注意,主查询中引用的外部作用域变量 person 在 WITH 子句之后依然可用。
MATCH (person:Person)
WHERE COUNT {
WITH "Ozzy" AS dogName
MATCH (person)-[:HAS_DOG]->(d:Dog)
WHERE d.name = dogName
} = 1
RETURN person.name AS name
| 名称 (name) |
|---|
|
行:1 |
在其他子句内使用 COUNT 子查询
COUNT 可用于查询中的任何位置,管理命令除外(在管理命令中受到限制)。请查看以下几个示例:
在 RETURN 中使用 COUNT
MATCH (person:Person)
RETURN person.name, COUNT { (person)-[:HAS_DOG]->(:Dog) } as howManyDogs
| person.name | 狗的数量 |
|---|---|
|
|
|
|
|
|
行:3 |
|
在 SET 中使用 COUNT
MATCH (person:Person) WHERE person.name ="Andy"
SET person.howManyDogs = COUNT { (person)-[:HAS_DOG]->(:Dog) }
RETURN person.howManyDogs as howManyDogs
| 狗的数量 |
|---|
|
行:1 |
在 CASE 中使用 COUNT
MATCH (person:Person)
RETURN
CASE
WHEN COUNT { (person)-[:HAS_DOG]->(:Dog) } > 1 THEN "Doglover " + person.name
ELSE person.name
END AS result
| 结果 |
|---|
|
|
|
行:3 |
将 COUNT 用作分组键
以下查询根据每个人拥有的狗的数量对所有人进行分组,然后计算每组的平均年龄。
MATCH (person:Person)
RETURN COUNT { (person)-[:HAS_DOG]->(:Dog) } AS numDogs,
avg(person.age) AS averageAge
ORDER BY numDogs
| 狗的数量 | 平均年龄 |
|---|---|
|
|
|
|
|
|
行:3 |
|
带 RETURN 的 COUNT 子查询
COUNT 子查询在子查询末尾不需要 RETURN 子句。如果存在 RETURN 子句,则不需要对其进行别名处理。这与 CALL 子查询 不同。在 COUNT 子查询中返回的任何变量在子查询结束后都将不可用。
MATCH (person:Person)
WHERE COUNT {
MATCH (person)-[:HAS_DOG]->(:Dog)
RETURN person.name
} = 1
RETURN person.name AS name
| 名称 (name) |
|---|
|
行:1 |
规则
以下规则适用于 COUNT 子查询:
-
允许使用任何非写入型查询。
-
最后的
RETURN子句可以省略,因为在子查询内定义的任何变量在表达式外部都不可用,即使使用了最后的RETURN子句也是如此。唯一的例外是,对于DISTINCT UNION子句,RETURN子句仍然是强制性的。 -
当
COUNT仅由一个模式和一个可选的WHERE子句组成时,可以省略子查询中的MATCH关键字。 -
COUNT子查询可以出现在查询中任何表达式有效的位置。 -
外部作用域中定义的任何变量都可以在
COUNT子查询自身的作用域内引用。 -
在
COUNT子查询内部引入的变量不属于外部作用域,因此无法在外部访问。