Cypher 与 SQL 的比较

尽管 Cypher® 和 SQL 之间存在关键区别,但仍然可以将这两种语言进行对比,并用 Cypher 编写等效的 SQL 语句。此处使用 Northwind 数据集来更好地说明这种对比。

有关图数据库与关系型数据库之间差异和相似之处的更深入解释,请参阅 从关系型数据库向图数据库转型

索引

SQL 和 Cypher 中都提供了索引。它们可以使针对特定节点标签和属性组合的搜索更加高效。

Cypher 中的索引仅用于查找查询的起点;所有后续的模式匹配均通过图结构完成。Cypher 支持范围索引、文本索引、点索引、查找索引、全文索引和向量索引。

在 Northwind 数据集中,为 productNameunitPrice 添加索引可以加快对产品及其价格的搜索速度。

SQL Cypher
CREATE INDEX Product_productName ON products (product_name);
CREATE INDEX Product_unitPrice ON products (unit_price);
CREATE INDEX Product_productName IF NOT EXISTS FOR (p:Product) ON p.productName;
CREATE INDEX Product_unitPrice IF NOT EXISTS FOR (p:Product) ON p.unitPrice;

查询示例

选择并返回记录

SQL Cypher

在 SQL 中,要选择并返回记录,需要从 products 表中选择所有内容。

SELECT p.*
FROM products as p;

在 Cypher 中,你可以 MATCH(匹配)一个简单的模式:所有具有 :Product 标签 的节点,并 RETURN(返回)它们。

MATCH (p:Product)
RETURN p;

字段访问、排序和分页

与其返回所有属性,不如过滤出你感兴趣的那些属性——例如 ProductNameUnitPrice

SQL Cypher

在 SQL 中,这是按价格排序并返回 10 个最昂贵条目的方法。

SELECT p.ProductName, p.UnitPrice
FROM products as p
ORDER BY p.UnitPrice DESC
LIMIT 10;

Cypher 中的语句与此类似,区别仅在于模式匹配部分。

MATCH (p:Product)
RETURN p.productName, p.unitPrice
ORDER BY p.unitPrice DESC
LIMIT 10;
结果
p.productName p.unitPrice

"Côte de Blaye"

263.5

"Thüringer Rostbratwurst"

123.79

"Mishi Kobe Niku"

97.0

"Sir Rodney’s Marmalade"

81.0

"Carnarvon Tigers"

62.5

"Raclette Courdavault"

55.0

"Manjimup Dried Apples"

53.0

"Tarte au sucre"

49.3

"Ipoh Coffee"

46.0

"Rössle Sauerkraut"

45.6

请记住,Neo4j 中的标签、关系类型和属性名称是区分大小写的。有关命名规则的更多详细信息,请参阅 Cypher 手册 → 命名规则和建议

按名称查找单个产品

有多种方法可以查询数据库并检索单个项目,例如名为 Chocolade 的产品。你可以通过相等性过滤来实现这一点。

SQL Cypher

在 SQL 中,你可以使用 WHERE 子句过滤数据。

SELECT p.ProductName, p.UnitPrice
FROM products AS p
WHERE p.ProductName = 'Chocolade';

在 Cypher 中,WHERE 子句属于 MATCH 语句的一部分。

MATCH (p:Product)
WHERE p.productName = 'Chocolade'
RETURN p.productName, p.unitPrice;

一个更简短的选择是在 MATCH 语句中使用 productName 标签来指定产品。

MATCH (p:Product {productName:'Chocolade'})
RETURN p.productName, p.unitPrice;
结果
p.productName p.unitPrice

"Chocolade"

12.75

过滤产品

按列表/范围过滤

SQL Cypher

在 SQL 中,你可以使用 IN 操作符。

SELECT p.ProductName, p.UnitPrice
FROM products as p
WHERE p.ProductName IN ('Chocolade','Chai');

Cypher 提供完整的集合支持,包括 IN 以及其他集合函数、谓词和转换。

MATCH (p:Product)
WHERE p.productName IN ['Chocolade','Chai']
RETURN p.productName, p.unitPrice;
结果
p.productName p.unitPrice

"Chocolade"

12.75

"Chai"

18.0

按多个数字和文本谓词过滤

SQL Cypher

此查询检索名称以 "C" 开头且价格大于 100 的产品。

SELECT p.ProductName, p.UnitPrice
FROM products AS p
WHERE p.ProductName LIKE 'C%' AND p.UnitPrice > 100;

在 Cypher 中,LIKE 操作符被 STARTS WITHCONTAINSENDS WITH 操作符所取代。

MATCH (p:Product)
WHERE p.productName STARTS WITH 'C' AND p.unitPrice > 100
RETURN p.productName, p.unitPrice;

你还可以使用正则表达式获取所有名称以 "C" 开头的产品及其价格。

MATCH (p:Product)
WHERE p.productName =~ '^C.*'
RETURN p.productName, p.unitPrice
结果
p.productName p.unitPrice

"Côte de Blaye"

263.5

连接产品与客户

SQL Cypher

在 SQL 中,如果你想查看是谁购买了 Chocolade,可以将这四个表连接在一起。

SELECT DISTINCT c.CompanyName
FROM customers AS c
JOIN orders AS o ON (c.CustomerID = o.CustomerID)
JOIN order_details AS od ON (o.OrderID = od.OrderID)
JOIN products AS p ON (od.ProductID = p.ProductID)
WHERE p.ProductName = 'Chocolade';

在 Cypher 中,无需使用 JOIN 连接表。你可以直接将连接表达为图模式。

MATCH (p:Product {productName:'Chocolade'})<-[:ORDERS]-(:Order)<-[:PURCHASED]-(c:Customer)
RETURN DISTINCT c.companyName;
结果
c.companyName

"Victuailles en stock"

"Ernst Handel"

"Antonio Moreno Taquería"

"Furia Bacalhau e Frutos do Mar"

"Around the Horn"

"Queen Cozinha"

每个产品的总支出

通过对产品价格和订购数量求和,可以提供每个客户针对各产品的汇总视图。你可以在 SQL 和 Cypher 中使用 sumcountavgmax 等聚合函数。

SQL Cypher

如果你想查看某家公司(例如 Drachenblut Delikatessen)在每个产品上的总支出(包括未订购某些产品的情况),你必须使用 OUTER JOIN,以确保即使在其他表中没有匹配行时也能返回结果。

SELECT p.Product_Name, sum(od.Unit_Price * od.Quantity) AS TotalPrice
FROM customers AS c
LEFT OUTER JOIN orders AS o ON (c.Customer_ID = o.Customer_ID)
LEFT OUTER JOIN order_details AS od ON (o.Order_ID = od.Order_ID)
LEFT OUTER JOIN products AS p ON (od.Product_ID = p.Product_ID)
WHERE c.Company_Name = 'Drachenblut Delikatessen'
GROUP BY p.Product_Name;

在 Cypher 中,你需要将 ORDERS 关系的 unitPrice 属性转换为整数,以便在订购数量和花费金额之间进行计算。

MATCH (p:Product)<-[o:ORDERS]-(order:Order)
SET o.unitPrice = toInteger(o.unitPrice)
RETURN o

然后,你 MATCH 你想要收集信息的公司,并使用 OPTIONAL MATCH 来查找他们的购买记录和获取的产品,最后 RETURN 总和。

MATCH (c:Customer {companyName:'Drachenblut Delikatessen'})
OPTIONAL MATCH (c)-[:PURCHASED]->(:Order)-[o:ORDERS]->(p:Product)
RETURN p.productName, toInteger(sum(o.unitPrice * o.quantity)) AS totalPrice
结果
p.productName totalPrice

"Gumbär Gummibärchen"

372

"Perth Pasties"

640

"Konbu"

114

"Jack’s New England Clam Chowder"

81

"Queso Cabrales"

420

"Raclette Courdavault"

1650

"Lakkalikööri"

168

"Rhönbräu Klosterbier"

72

"Gorgonzola Telino"

200

供应产品的数量

前面的示例提到了聚合,并使用了 SUM 函数来计算公司在购买特定产品时的花费。你也可以在 Cypher 中使用 COUNT 函数来统计供应商提供的产品数量。

SQL Cypher

在 SQL 中,聚合是显式的,因此你必须在 GROUP BY 子句中提供所有分组键。

SELECT s.CompanyName AS Supplier, COUNT(p.ProductID) AS NumberOfProducts
FROM Suppliers s
JOIN Products p ON s.SupplierID = p.SupplierID
GROUP BY s.CompanyName
ORDER BY NumberOfProducts DESC
LIMIT 5;

在 Cypher 中,用于聚合的分组是隐式的。一旦你使用了第一个聚合函数,所有未聚合的列都会自动成为分组键。

MATCH (s:Supplier)<-[:SUPPLIED_BY]-(p:Product)
RETURN s.companyName AS Supplier, COUNT(p) AS NumberOfProducts
ORDER BY NumberOfProducts DESC
LIMIT 5

还提供了其他聚合函数,如 collectpercentileContstdDev

结果
供应商 产品数量

"Pavlova"

5

"Plutzer Lebensmittelgroßmärkte AG"

5

"Specialty Biscuits"

4

"New Orleans Cajun Delights"

4

"Grandma Kelly’s Homestead"

3

供应产品列表

在 Cypher 中,你可以使用 COLLECT 函数来收集所有连接到其他节点的节点,但 SQL 没有直接的对应物。

SQL Cypher

在 SQL 中,如果你想要供应商提供产品的列表,可以使用 STRING_AGG

SELECT s.CompanyName AS Supplier, STRING_AGG(p.ProductName, ', ' ORDER BY p.ProductName) AS ProductsSupplied
FROM Suppliers s
JOIN Products p ON s.SupplierID = p.SupplierID
GROUP BY s.CompanyName
ORDER BY s.CompanyName
LIMIT 5;

在 Cypher 中,你可以像在 SQL 中那样返回结构,也可以使用 collect() 聚合函数,将值聚合到一个集合(列表、数组)中。这样,每个父级仅返回一行,其中包含子值的内联集合。

MATCH (s:Supplier)-[:SUPPLIES]->(p:Product)
RETURN s.companyName AS Supplier, COLLECT(p.productName) AS ProductsSupplied
ORDER BY Supplier
LIMIT 5

这同样适用于嵌套值。

结果
供应商 供应产品

"Aux joyeux ecclésiastiques"

["Côte de Blaye", "Chartreuse verte"]

"Bigfoot Breweries"

["Sasquatch Ale", "Laughing Lumberjack Lager", "Steeleye Stout"]

"Cooperativa de Quesos 'Las Cabras'"

["Queso Manchego La Pastora", "Queso Cabrales"]

"Escargots Nouveaux"

["Escargots de Bourgogne"]

"Exotic Liquids"

["Aniseed Syrup", "Chang", "Chai"]