关系型数据库的查询语言是SQL,Neo4j 图数据库也有自己的查询语言,那就是CQL。
CQL全称Cypher Query Language,它是一种声明性的模式匹配语言,跟SQL非常类似,也遵循SQL的语法。
CQL的语句书写起来都非常简单,而且很人性化,可读性强。
如果熟悉SQL,那么CQL的语法很容易就学会了。 下面通过表格列出 CQL 中常用的一些命令和函数。
第一个是CQL常用命令
| 命令/释义 | 用途 |
|---|---|
| create/创建 | 创建节点、关系或属性 |
| match/匹配 | 获取有关节点、关系或属性的数据 |
| return/返回 | 返回最终需要的查询结果 |
| where/条件 | 根据条件过滤数据 |
| delete/删除 | 删除节点、关系 |
| remove/移除 | 删除节点和关系的属性、标签 |
| order by/排序 | 对最终结果进行排序 |
| set/组 | 添加或者更新标签、属性 |
第二个是CQL常用函数
| 函数/释义 | 用途 |
|---|---|
| Aggregation/聚合 | 对查询结果执行一些聚合操作 |
| Relationship/关系 | 获取关系的细节,如startnode,endnode等 |
| String/字符串 | 使用字符串的功能,例如截取子串、替换等 |
create命令可以用于创建节点,有两种语法,分别对应创建无属性的节点和有属性的节点。
//无属性
create (<node-name>:<label-name>)
//有属性
create (
<node-name>:<label-name>
{
<Property1-name>:<Property1-Value>
........
<PropertyN-name>:<PropertyN-Value>
}
)
node-name是要创建的节点的具体名称,label-name是节点所属的标签的名称。即,一个标签要管理一组节点。
property-name和property-value是键值对,定义该节点的一个属性,即该属性的名称和值。
这里有个重要的点,那就是使用create命令一定会创建节点。当创建节点时,节点内部都会自带一个ID属性,该ID的值由系统内部自动分配,所以,就算定义两个节点的属性值全部相同,但是其内部ID值一定不同,系统会将他们视为两个独立节点。
示例如下:
//在数据库中创建了两个节点zhangsan和lisi,他们都属于标签Student。
create (zhangsan:Student)
create (lisi:Student)
//创建了一个节点xiaoming,也属于标签Student,有三个属性:id、name。dept
create (
xiaoming:Student
{
id: 001,
age:20,
dept:"CS"
}
)
create也可以创建一个节点对应多个标签,语法为:
create (<node-name>:<label-name1>:<label-name2>.....:<label-nameN>)
示例:
create (xiaobai:Boy:Student:Person)
//这里xiaobai是节点名,Boy、Student、Person是该节点的多个标签名称
create还可以用于创建节点之间的关系,语法为:
create (<node1-name>:<label1-name>)-
[<relationship-name>:<relationship-label-name>]
->(<node2-name>:<label2-name>)
relationship-name是要创建的关系的具体名称,relationship-label-name是关系的标签名称。
具体示例如下,创建了两个节点,并且从节点b1到g1有一个单向的关系
create (b1:Boy)-[r1:Likes]->(g1:Girl)
注意,Neo4j中两个节点之间的关系是有方向性的,使用了箭头进行标记:() - []→()。如果没有使用箭头标记关系的方向:() - [] - (),那么Neo4j服务器会报错。
match命令语法为:
match
(
<node-name>:<label-name>
)
这里有个很重要的注意事项,不能单独使用match语句,必须和其他语句进行配合。如果单独使用match,系统将报错InvalidSyntax,我们使用时match经常与return配合。
return命令语法为:
return
<node-name>.<property1-name>,
······
<node-name>.<propertyN-name>
return语句也是不能单独使用的,应该与match或者create语句配合。
match配合return语句示例:
//检索Student标签下xiaoming节点的某几个属性
match (xiaoming:Student)
return xiaoming.id, xiaoming.age
//检索Student标签下xiaoming节点的所有属性
match (xiaoming:Student)
return xiaoming
where命令的用法和SQL完全一样,就是通过限制条件来过滤数据
//简单where
where <condition>
//复杂where
where <condition> <boolean-operator> <condition>
condition就是筛选条件,包括小于、大于、小于等于、大于等于、等于、不等于六种选择,例如 id>100,age<=20 等。值得注意的是,不等于用 <> 来进行表示。
boolean-operator就是布尔运算符,包括 AND、OR、NOT、XOR 四种,分别对应与、或、非、异或四种操作。
示例如下,假设现在数据库中有2个年龄20岁和2个年龄21岁的学生(标签Student),名字分别是zhangsan、lisi、zhangsan、lisi。
//查询年龄为21的学生
match (stu:Student)
where stu.age=21
return stu
//查询年龄为20且名字为zhangsan的学生
match (stu:student)
whhere stu.age=20 and stu.name="zhangsan"
return stu
delete的删除方式有两种,一种是直接删除节点,但是要求删除的节点不能与其他节点有关系连接;另一种是将节点和关系一起删除。
//删除节点
delete <node-namelist>
//删除节点及其关系
delete <node1-name>,<node2-name>,<relationship-name>
示例如下,这里删除的都是之前create的节点
//删除节点
match (zhangsan:Student) delete zhangsan
//删除节点及其关系
match (b1:Boy)-[r1]-(g1:Girl)
delete b1,g1,r1
delete与remove的相同点:
两者都不能单独使用两者都应该和match命令配合使用delete和remove的不同点:
remove语法:
//删除节点或关系的属性
remove <property-name-list>
//删除节点或关系的标签
remove <label-name-list>
示例如下:
//先创建节点
create (stu1:Student {sid:003,name:"xiao bai",age:19,dept:"SE"})
create (xiaohong:Girl:Student:Person)
//删除“dept”属性
match (stu1{sid:003})
remove stu1.dept
return stu1
//删除student、person标签
match (xiaohong:Girl)
remove xiaohong:Student,xiaohong:Person
set语法:
//添加/更新属性
set <property-name-list>
示例如下:
//先创建节点
create (stu2:Student {sid:004,name:"xiao gang",age:20,dept:"SE"})
//添加属性class
match (stu2:Student)
where stu2.dept="SE"
set stu2.class = "SE01"
return stu2
//已经存在属性class,则会将其更改为SE02
match (stu2:Student)
where stu2.dept="SE"
set stu2.class = "SE02"
return stu2
order by命令可以对match查询的结果进行排序,默认是升序排序,语法如下:
//升序
ORDER BY <property-name-list>
//降序使用关键字 desc
ORDER BY <property-name-list> desc
示例如下,假设数据库中存在5本书(标签Book),id分别为001至005,price分别是20、40、30、50、10
//按价格升序
match (book:Book)
return book
order by book.price
//按id降序
match (book:Book)
return book
order by book.id desc
字符串常用函数一共是四个
| 函数 | 效果 |
|---|---|
| upper | 将字符串中的所有字母更改为大写字母 |
| lower | 将字符串中的所有字母更改为小写字母 |
| substring | 获取所给字符串的指定子字符串 |
| replace | 替换所给字符串的子字符串 |
函数语法如下:
取值区间左闭右开。endIndex可以省略,省略时默认到字符串的结尾upper (<input-String>)
lower (<input-string>)
substring (<input-string>,<startIndex> ,<endIndex>)
replace (<input-string>,<startString> ,<endString>)
示例如下:
create (
b:Book
{
name:"WildGrass",
price:30
}
)
//结果为 WILDGRASS、wildgrass、wild、HomeGrass
match (b:Book)
return upper(b.name),lower(b.name),substring(b.name,0,4),replace(b.name,"Wild","Home")
这里需要注意,b.name的值一直是“WildGrass”。因为字符串函数用在return里面都作用于查询的数据,不会更改数据库中节点属性原本的值。
聚合函数的用法和SQL中完全一致
| 函数 | 效果 |
|---|---|
| count | 统计match命令返回的行数 |
| max | 找到match命令返回的一组行中的最大值 |
| min | 找到match命令返回的一组行中的最小值 |
| sum | 统计match命令返回的一组行的值求和 |
| avg | 统计match命令返回的一组行的值求平均值 |
函数语法如下:
count(<value>) //<value>可以是*,节点或关系标签名称或属性名称
max(<property-name>)
min(<property-name>)
sum(<property-name>)
avg(<property-name>)
示例如下,假设数据库中存在5本书(标签Book),id分别为001至005,price分别是20、40、30、50、10
//结果为5
match (book:Book) return count(*)
//结果为50、10、150、50
match (book:Book)
return max(book.price),min(book.price),sum(book.price),avg(book.price)
CQL的关系函数可以在获取开始节点,结束节点等细节时知道该关系的细节。
| 函数 | 效果 |
|---|---|
| startnode | 获取关系的开始节点 |
| endnode | 获取关系的结束节点 |
| id | 获取关系的ID |
| type | 获取关系的类型信息 |
这里的 id 就是我们在create命令中提到的内部ID。
函数语法如下:
startnode (<relationship-label-name>)
endnode (<relationship-label-name>)
id (<relationship-name>)
type (<relationship-name>)
示例如下:
//先创建关系
create (b101:Boy)-[r101:Likes]->(g101:Girl)
create (s201:Student)-[r201:Read]->(b201:Book)
//获取指定关系的开始和结束节点
match (b)-[r:Likes]->(g)
return startnode(r),endnode(r)
//获取指定关系的id和type
match (s)-[r:Read]->(b)
return id(r),type(r)
//如果不指定关系,那么将会把所有类型的关系都查询出来
match (b)-[r]->(g)
return id(r),type(r)