meface/docs/article/db/neo4j_cypher.md

309 lines
7.4 KiB
Markdown
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

## Neo4j的cyhper基本语法
### 1. 创建节点和关系
#### 1.1创建节点
```sql
create (n)
create (n),(m)
create(n:Movie)
create(n:Movie:Person)
# 创建一个带有标签(Person)和属性(name:'TEST-NAME', age:1)的节点
create(n:Person {name:'qiusj',age:18})
# 返回创建的节点
CREATE(n:TEST {name:'TEST-NAME1', age:2}) return n
```
#### 1.2 创建关系
```sql
# 创建两个节点之间的关系
MATCH (a:TEST),(b:TEST)
WHERE a.name = 'TEST-NAME' AND b.name = 'TEST-NAME1'
CREATE (a)-[r:RELTYPE] -> (b)
RETURN r
# 创建两个节点之间的关系,并调用两个节点的属性:
MATCH (a:TEST),(b:TEST)
WHERE a.name = 'TEST-NAME' AND b.name = 'TEST-NAME1'
CREATE (a)-[r:RELTYPE { name: a.name + b.name}] -> (b)
RETURN r
```
#### 1.3 `merge` 命令
在Neo4j数据库中**MERGE**命令是一个非常强大的工具,它结合了**CREATE**和**MATCH**命令的功能。当你需要确保一个特定的节点或关系在图中存在时MERGE命令就显得尤为重要。如果该节点或关系不存在MERGE将会创建它如果已经存在MERGE则会匹配到这个现有的元素。
> 如果这个节点已经存在那么MERGE命令的作用就相当于MATCH命令。判断是否存在的方式是表达式中所有的属性组合匹配的如 MERGE (p:Person {name: 'Alice'}) RETURN p;只要在已有的Person中name属性没有等于'Alice'的就是不存在MERGE (p:Person {name: 'Alice,age:18}) 则要求现有的Person中的name和age都不相同才表示不存在
```sql
MERGE (robert:Person { name: 'Robert' })
RETURN robert, labels(robert)
```
MERGE还可以用来创建节点之间的关系。如果两个节点之间的关系不存在MERGE会创建这个关系。例如以下命令会创建一个名为"Robert"的Person节点和一个名为"hanscal"的Person节点之间的FAMILY关系:
```sql
MATCH (n:Person { name: 'Robert' }), (m:Person { name: "hanscal" })
MERGE (n)-[r:FAMILY]->(m)
RETURN n.name, type(r), m.name
```
**使用ON CREATE和ON MATCH**
MERGE命令可以与**ON CREATE**和**ON MATCH**子句结合使用,这允许你根据元素是被匹配到还是被创建来执行不同的操作。例如,以下命令在创建新节点时设置一个时间戳属性:
```sql
MERGE (c:Person { name: 'Hanscal' })
ON CREATE SET c.create = timestamp()
RETURN c.name, c.create
```
如果节点"Hanscal"已经存在,则不会设置任何属性。相反,如果使用**ON MATCH**,则只有在匹配到节点时才会设置属性。
**批量操作**
MERGE命令也可以用于批量操作快速创建大量的节点和关系。例如以下命令会将所有Person节点的出生地属性与City节点连接起来并创建BORN_IN关系
```sql
MATCH (person:Person)
MERGE (city:City { name: person.bornIn })
MERGE (person)-[r:BORN_IN]->(city)
RETURN person.name, person.bornIn, city
```
总的来说,`MERGE`命令在确保数据一致性和避免重复创建相同的元素时非常有用。
**约束与 MERGE 命令的关系**
- **唯一性约束**:确保指定标签的节点在特定属性上具有唯一性,是 Neo4j 保证数据完整性的重要机制
- MERGE 命令行为:
- 若匹配条件的节点 / 关系存在,则返回现有节点 / 关系
- 若不存在,则创建新的节点 / 关系
- **冲突点**:当 MERGE 的匹配条件触发唯一性约束时,会因重复数据导致操作失败
#### 1.4 添加属性
方案 1使用 MATCH 而非 MERGE推荐
```sql
MATCH (p:Person {name: 'Robert'})
SET p.age = 18
RETURN p;
```
方案 2修改 MERGE 语句避免重复创建
```sql
# 安全的MERGE写法(先检查节点是否存在)
MERGE (p:Person {name: 'Robert'})
# 仅当节点不存在时才创建新属性(避免冲突)
ON CREATE SET p.create = timestamp()
# 无论是否创建都可以设置属性(不会触发约束)
SET p.money = 1
RETURN p;
```
#### 1.5 修改节点的关系类型
在 Neo4j 中关系类型Relationship Type是不可变的无法直接修改。若要更改关系类型需通过以下步骤实现**创建新关系 → 复制属性 → 删除旧关系**。以下是详细方法:
**方法一:使用 Cypher 手动转换关系类型**
```sql
// 示例:将 KNOWS 关系转换为 FRIEND 关系
MATCH (p1:Person)-[r:KNOWS]->(p2:Person)
WHERE p1.name = 'Alice' AND p2.name = 'Bob'
// 创建新类型的关系
CREATE (p1)-[r2:FRIEND]->(p2)
// 复制旧关系的所有属性到新关系
SET r2 = r
// 删除旧关系
DELETE r
RETURN p1, r2, p2;
```
### 2.查询语法
> match、optional match、where、start和aggregation聚合
#### 2.1 match语法
**简单查询**
```sql
# 查询所有节点
match (n) return n
# 查询指定标签的节点
match (n:Person) return n
# 查询指定标签和属性的节点
match (n:Person {name:"张三"}) return n
```
**关系查询**
```sql
# 查询出度1的节点
match (n:Person{name:"张三"})-[r]->(m) return m
match (n:Person{name:"zhangsan"})-->(m) return m
# 查询入度1节点:
match (n:Person{name:"zhangsan"})<-[r]-(m) return m
match (n:Person{name:"zhangsan"})<--(m) return m
```
### 3.删除节点
- 删除无关系的孤立节点
使用`DELETE`语句直接删除节点
```sql
// 删除单个节点(无关系)
MATCH (p:Person {name: 'Alice'})
DELETE p;
// 批量删除符合条件的节点
MATCH (p:Person)
WHERE p.age < 18
DELETE p;
```
- 删除带有关联关系的节点
需先删除关系再删除节点可使用`DETACH DELETE`一次性完成
```sql
// 方法1分步删除手动删除关系
MATCH (p:Person {name: 'Bob'})-[r]->()
DELETE r; // 先删除所有外出关系
MATCH (p:Person {name: 'Bob'})
DELETE p; // 再删除节点
// 方法2使用DETACH DELETE推荐
MATCH (p:Person {name: 'Charlie'})
DETACH DELETE p; // 自动删除节点及其所有关系
```
- 基于关系条件删除节点
删除符合特定关系条件的节点:
```sql
// 删除所有没有朋友的人无FOLLOWS关系
MATCH (p:Person)
WHERE NOT (p)-[:FOLLOWS]->()
DELETE p;
// 删除被超过100人关注的明星节点
MATCH (s:Star)<-[r:FOLLOWS]-()
WITH s, count(r) as followers
WHERE followers > 100
DETACH DELETE s;
```
- 删除整个标签的所有节点
```sql
// 删除所有Person节点及其关系
MATCH (p:Person)
DETACH DELETE p;
// 更安全的分批删除方法
CALL apoc.periodic.iterate(
"MATCH (p:Person) RETURN p",
"DETACH DELETE p",
{batchSize:1000, parallel:false}
);
```
- 删除节点并返回删除数量
```sql
MATCH (p:Person)
WHERE p.lastLogin < date("2023-01-01")
DETACH DELETE p
RETURN count(*) as deletedNodes;
```
### 4. 删除关系
场景一删除特定关系
```sql
// 方法1:通过匹配节点和关系类型删除
MATCH (p1:Person {name: 'Alice'})-[r:FRIEND]->(p2:Person {name: 'Bob'})
DELETE r;
// 方法2:使用更精确的匹配条件(如属性)
MATCH (p1:Person)-[r:WORKS_ON {projectId: 'PRJ-123'}]->(p2:Project)
DELETE r;
```
场景二只有查询返回的ID
```sql
// 方法1:使用关系ID直接删除
MATCH ()-[r]->()
WHERE id(r) = 5678 // 替换为实际关系ID
DELETE r; // 仅删除关系,保留节点
// 方法2:验证关系后删除
MATCH ()-[r]->()
WHERE id(r) = 5678
RETURN r; // 先查询确认关系是否存在
// 确认无误后执行删除
MATCH ()-[r]->()
WHERE id(r) = 5678
DELETE r;
```