翻译:https://arangodb.com/why-arangodb/sql-aql-comparison/
SQL/AQL-比较
ArangoDB查询语言(AQL)与结构化查询语言(SQL)的目的类似。两者都支持读取和修改收集数据,但是AQL不支持数据定义操作,比如创建和删除数据库、集合和索引。尽管一些关键字重叠,但AQL语法与SQL不同。例如,SQL WHERE和AQL FILTER子句是等价的,它们都定义了返回结果的条件。但是,SQL使用预定义的序列来确定WHERE子句必须在语句中出现的位置。在AQL中,子句从左到右执行,因此查询中的FILTER子句的位置决定了它的优先级。
术语
下面是两个系统的术语表。
SQL | AQL |
database | database |
table | collection |
row | document |
column | attribute |
table joins | collection joins |
primary key | primary key (automatically present on _key attribute) |
index | index |
INSERT
INSERT关键字将新文档添加到一个集合中。它使用以下语法:INSERT document INTO collection options
插入单行/单文件
SQL:
12 INSERT INTO users ( name , gender )VALUES ( "John Doe" , "m" ) ;AQL:
12 INSERT { name : "John Doe" , gender : "m" }INTO users
插入单行/单文件
SQL:
123 INSERT INTO users ( name , gender )VALUES ( "John Doe" , "m" ) ,( "Jane Smith" , "f" ) ;AQL:
12345 FOR user IN [{ name : "John Doe" , gender : "m" } ,{ name : "Jane Smith" , gender : "f" }]INSERT user INTO users
从表或集合中数据迁移
SQL:
1234 INSERT INTO backup ( uid , name , gender )SELECT uid , name , genderFROM usersWHERE active = 1 ;AQL:
123 FOR user IN usersFILTER user . active == 1INSERT user INTO backup
循环导入
SQL:
使用脚本或者存储过程实现
AQL:
123456 FOR i IN 1..1000INSERT {name : CONCAT ( "test" , i ) ,gender : ( i % 2 == 0 ? "f" : "m" )}INTO users
UPDATE
|
UPDATE
document
IN
collection
options
UPDATE
keyExpression
WITH
document
IN
collection
options
|
更新单行/文件
SQL:
123 UPDATE usersSET name = "John Smith"WHERE id = 1 ;AQL:
123 UPDATE { _key : "1" }WITH { name : "John Smith" }IN users
添加新字段/属性(默认值)
SQL:
123 ALTER TABLE usersADD COLUMN numberOfLoginsINTEGER NOT NULL default 0 ;AQL:
123 FOR user IN usersUPDATE userWITH { numberOfLogins : 0 } IN users
2
|
UPDATE
document
IN
collection
options
UPDATE
keyExpression
WITH
document
IN
collection
options
|
添加新字段/属性(计算值)
SQL:
123456789 ALTER TABLE usersADD COLUMN numberOfLogins INTEGERNOT NULL default 0 ;UPDATE usersSET numberOfLogins = (SELECT COUNT ( * ) FROM loginsWHERE user = users . id)WHERE active = 1 ;AQL:
1234567891011 FOR user IN usersFILTER user . active == 1UPDATE userWITH {numberOfLogins : LENGTH (FOR login IN loginsFILTER login . user == user . _keyCOLLECT WITH COUNT INTO numLoginsRETURN numLogins)} IN users
删除字段/属性
SQL:
12 ALTER TABLE usersDROP COLUMN numberOfLogins ;AQL:
1234 FOR user IN usersUPDATE user WITH { numberOfLogins : null }IN usersOPTIONS { keepNull : false }
删除具体行的字段/属性
SQL: *
1234 UPDATE usersSET isImportantUser = NULL ,dateBecameImportant = NULLWHERE isImportantUser = 1 AND active = 0 ;AQL:
12345678910 FOR user IN usersFILTER user . isImportantUser == 1 ANDuser . active == 0UPDATE userWITH {isImportantUser : null ,dateBecameImportant : null}IN usersOPTIONS { keepNull : false }
REPLACE
12 REPLACE document IN collection optionsREPLACE keyExpression WITH document IN collection options
替换某行/文件
SQL:
123 REPLACE INTO users ( name , gender )VALUES ( "Jane Smith" , "f" )WHERE id = 1 ;AQL:
123456 REPLACE { _key : "1" }WITH {name : "Jane Smith" ,gender : "f"}IN users
替换多行/文件
SQL:
12 REPLACE INTO users ( name , gender )SELECT name , gender FROM backupAQL:
1234567 FOR user IN backupREPLACE userWITH {name : backup . name ,gender : backup . gender}IN users
DELETE/REMOVE
SQL使用DELETE语句来从表中删除行。在AQL中,REMOVE关键字允许您从集合中删除文档.
删除单行/文件
SQL:
12 DELETE FROM usersWHERE id = 1 ;AQL:
12 REMOVE { _key : "1" }IN users
删除多行/文件
SQL:
12 DELETE FROM usersWHERE active = 1 ;AQL:
123 FOR user IN usersFILTER user . active == 1REMOVE user IN users
QUERY
当您想从SQL中的表中检索行时,您可以使用SELECT语句查询数据库。在AQL中,使用FOR和RETURN关键字查询来自集合的文档。
这里,FOR在集合中对文档进行迭代。RETURN确定查询返回给客户端。
查询所有
SQL:
12 SELECT *FROM users ;AQL:
12 FOR user IN usersRETURN user
过滤查询
SQL:
123 SELECT CONCAT ( firstName , " " , lastName )AS name , gender FROM usersWHERE active = 1 ;AQL:
1234567 FOR user IN usersFILTER user . active == 1RETURN {name : CONCAT ( user . firstName , " " ,user . lastName ) ,gender : user . gender}
排序查询
SQL:
123 SELECT * FROM usersWHERE active = 1ORDER BY name , gender ;AQL:
1234 FOR user IN usersFILTER user . active == 1SORT user . name , user . genderRETURN user
AGGREGATION
在SQL和AQL中都有一系列函数和子句用于组或进一步细化结果集以获取所需的信息。例如,计算文档,查找最小值或最大值,等等。
分组统计
SQL:
123 SELECT gender , COUNT ( * ) AS number FROM usersWHERE active = 1GROUP BY gender ;AQL:
12345678 FOR user IN usersFILTER user . active == 1COLLECT gender = user . genderWITH COUNT INTO numberRETURN {gender : gender ,number : number}
分组
SQL:
1234567 SELECT YEAR ( dateRegister ) AS year ,MONTH ( dateRegister ) AS month ,COUNT ( * ) AS numberFROM usersWHERE active = 1GROUP BY year , monthHAVING number > 20 ;AQL:
123456789101112 FOR user IN usersFILTER user . active == 1COLLECTyear = DATE_YEAR ( user . dateRegistered ) ,month = DATE_MONTH ( user . dateRegistered )WITH COUNT INTO numberFILTER number > 20RETURN {year : year ,month : month ,number : number}
最大/最小计算
SQL:
1234 SELECT MIN ( dateRegistered ) AS minDate ,MAX ( dateRegistered ) AS maxDateFROM usersWHERE active = 1 ;AQL:
123456 FOR user IN usersFILTER user . active == 1COLLECT AGGREGATEminDate = MIN ( user . dateRegistered ) ,maxDate = MAX ( user . dateRegistered )RETURN { minDate , maxDate }
分组汇集
SQL: *
1234 SELECT gender , GROUP_CONCAT ( id ) AS userIdsFROM usersWHERE active = 1GROUP BY gender ;AQL:
12345678 FOR user IN usersFILTER user . active == 1COLLECT gender = user . genderINTO usersByGenderRETURN {gender : gender ,userIds : usersByGender [ * ] . user . _key}
JOINS
与关系数据库中的连接类似,ArangoDB也有自己的连接实现
内连接(inner join)
SQL:
123 SELECT * FROM usersINNER JOIN friendsON ( friends . user = users . id ) ;AQL:
可以通过嵌套FOR循环和使用filter语句:在AQL中轻松地表达内部连接。
1234 FOR user IN usersFOR friend IN friendsFILTER friend . user == user . _keyRETURN MERGE ( user , friend )注:
在AQL中,首选方法是从各个子属性的不同集合中返回文档部分,以避免属性名称冲突,例如:
1234 FOR user IN usersFOR friend IN friendsFILTER friend . user == user . _keyRETURN { user : user , friend : friend }还可以将匹配文档返回到水平列表中:
123456789 FOR user IN usersRETURN {user : user ,friends : (FOR friend IN friendsFILTER friend . user == user . _keyRETURN friend)}
外连接(outer join)
SQL:
123 SELECT * FROM usersLEFT JOIN friendsON ( friends . user = users . id ) ;AQL:
在AQL中没有直接支持外部连接,但是可以使用子查询实现:
1234567891011121314 FOR user IN usersLET friends = (FOR friend IN friendsFILTER friend . user == user . _keyRETURN friend)FOR friendToJoin IN (LENGTH ( friends ) > 0 ? friends :[ { /* no match exists */ } ])RETURN {user : user ,friend : friend}