WITH
示例图
以下示例使用具有以下模式的图
要重新创建图,请针对空的 Neo4j 数据库运行以下查询。
CREATE (techCorp:Supplier {name: 'TechCorp', email: 'contact@techcorp.com'}),
(foodies:Supplier {name: 'Foodies Inc.', email: 'info@foodies.com'}),
(laptop:Product {name: 'Laptop', price: 1000}),
(phone:Product {name: 'Phone', price: 500}),
(headphones:Product {name: 'Headphones', price: 250}),
(chocolate:Product {name: 'Chocolate', price: 5}),
(coffee:Product {name: 'Coffee', price: 10}),
(amir:Customer {firstName: 'Amir', lastName: 'Rahman', email: 'amir.rahman@example.com', discount: 0.1}),
(keisha:Customer {firstName: 'Keisha', lastName: 'Nguyen', email: 'keisha.nguyen@example.com', discount: 0.2}),
(mateo:Customer {firstName: 'Mateo', lastName: 'Ortega', email: 'mateo.ortega@example.com', discount: 0.05}),
(hannah:Customer {firstName: 'Hannah', lastName: 'Connor', email: 'hannah.connor@example.com', discount: 0.15}),
(leila:Customer {firstName: 'Leila', lastName: 'Haddad', email: 'leila.haddad@example.com', discount: 0.1}),
(niko:Customer {firstName: 'Niko', lastName: 'Petrov', email: 'niko.petrov@example.com', discount: 0.25}),
(yusuf:Customer {firstName: 'Yusuf', lastName: 'Abdi', email: 'yusuf.abdi@example.com', discount: 0.1}),
(amir)-[:BUYS {date: date('2024-10-09')}]->(laptop),
(amir)-[:BUYS {date: date('2025-01-10')}]->(chocolate),
(keisha)-[:BUYS {date: date('2023-07-09')}]->(headphones),
(mateo)-[:BUYS {date: date('2025-03-05')}]->(chocolate),
(mateo)-[:BUYS {date: date('2025-03-05')}]->(coffee),
(mateo)-[:BUYS {date: date('2024-04-11')}]->(laptop),
(hannah)-[:BUYS {date: date('2023-12-11')}]->(coffee),
(hannah)-[:BUYS {date: date('2024-06-02')}]->(headphones),
(leila)-[:BUYS {date: date('2023-05-17')}]->(laptop),
(niko)-[:BUYS {date: date('2025-02-27')}]->(phone),
(niko)-[:BUYS {date: date('2024-08-23')}]->(headphones),
(niko)-[:BUYS {date: date('2024-12-24')}]->(coffee),
(yusuf)-[:BUYS {date: date('2024-12-24')}]->(chocolate),
(yusuf)-[:BUYS {date: date('2025-01-02')}]->(laptop),
(techCorp)-[:SUPPLIES]->(laptop),
(techCorp)-[:SUPPLIES]->(phone),
(techCorp)-[:SUPPLIES]->(headphones),
(foodies)-[:SUPPLIES]->(chocolate),
(foodies)-[:SUPPLIES]->(coffee)
创建新变量
WITH
可以与 AS
关键字结合使用,以绑定新变量,然后这些变量可以传递给后续子句。
WITH [1, 2, 3] AS list
RETURN list
列表 |
---|
|
行数:1 |
在下面的示例中,WITH
子句将所有匹配的 Customer
节点绑定到一个新变量 customers
。绑定的节点是 MAP
值,可以从新变量中引用。
MATCH (c:Customer)-[:BUYS]->(:Product {name: 'Chocolate'})
WITH c AS customers
RETURN customers.firstName AS chocolateCustomers
chocolateCustomers |
---|
|
|
|
行数:3 |
控制作用域中的变量
WITH
可用于控制哪些变量保留在查询的作用域内。任何被 WITH
子句引用的变量都将保留在查询的作用域内,并可供后续子句使用。如果变量在 WITH
子句中被重命名,则后续子句只能通过其新名称引用它。如果变量在 WITH
子句中未被显式引用,则它将从查询的作用域中删除,并且不能被后续子句引用。要保留查询作用域中的所有变量,请使用 WITH *
。
在下面的查询中,WITH
子句取消了 p
变量的作用域。因此,它不能被后续的 RETURN
子句使用。同样,c
变量也无法使用——由于前面的 WITH
子句,只有 chocolateCustomers
可用。
MATCH (c:Customer)-[:BUYS]->(p:Product {name: 'Chocolate'})
WITH c.name AS chocolateCustomers
RETURN chocolateCustomers,
p.price AS chocolatePrice
Variable `p` not defined
WITH *
保留所有变量MATCH (supplier:Supplier)-[r]->(product:Product)
WITH *
RETURN supplier.name AS company,
type(r) AS relType,
product.name AS product
company | relType | product |
---|---|---|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
行数:5 |
WITH
无法取消导入到 CALL
子查询 的变量的作用域,因为导入到子查询的变量被认为是其内部作用域的全局变量。更具体地说,即使前面的 WITH
子句未引用它,导入到 CALL
子查询中的变量也将可供后续子句使用。
在下面的示例中,x
变量被导入到 CALL
子查询的内部作用域,即使前面的 WITH
未列出它,RETURN
子句也成功引用了它。
WITH 11 AS x
CALL (x) {
UNWIND [2, 3] AS y
WITH y
RETURN x*y AS a
}
RETURN x, a
x | a |
---|---|
|
|
|
|
行数:2 |
有关更多信息,请参阅 CALL
子查询 → 导入变量。
将值绑定到变量
WITH
可用于将表达式的值赋给变量。在下面的查询中,STRING
连接表达式的值绑定到一个新变量 customerFullName
,表达式 chocolate.price * (1 - customer.discount)
的值绑定到 chocolateNetPrice
,这两个变量随后都可在 RETURN
子句中使用。
MATCH (customer:Customer)-[:BUYS]->(chocolate:Product {name: 'Chocolate'})
WITH customer.firstName || ' ' || customer.lastName AS customerFullName,
chocolate.price * (1 - customer.discount) AS chocolateNetPrice
RETURN customerFullName,
chocolateNetPrice
customerFullName | chocolateNetPrice |
---|---|
|
|
|
|
|
|
行数:3 |
因为 WITH
可用于将变量赋给表达式的值,所以它可用于链式表达式。
WITH
链式表达式MATCH (p:Product)
WITH p, p.price >= 500 AS isExpensive
WITH p, isExpensive, NOT isExpensive AS isAffordable
WITH p, isExpensive, isAffordable,
CASE
WHEN isExpensive THEN 'High-end'
ELSE 'Budget'
END AS discountCategory
RETURN p.name AS product,
p.price AS price,
isAffordable,
discountCategory
ORDER BY price
product | price | isAffordable | discountCategory |
---|---|---|---|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
行数:5 |
聚合
WITH
子句可以执行聚合并将结果绑定到新变量。在此示例中,sum()
函数用于计算每个客户的总支出,每个值都绑定到新变量 totalSpent
。 collect()
函数用于将每个产品收集到绑定到 productsBought
变量的 LIST
值中。
WITH
执行聚合MATCH (c:Customer)-[:BUYS]->(p:Product)
WITH c.firstName AS customer,
sum(p.price) AS totalSpent,
collect(p.name) AS productsBought
RETURN customer,
totalSpent,
productsBought
ORDER BY totalSpent DESC
customer | totalSpent | productsBought |
---|---|---|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
行数:7 |
删除重复值
如果 WITH
附加修饰符 DISTINCT
,则可用于从结果集中删除重复值。
在下面的查询中,WITH DISTINCT
用于从 Customer
节点中删除任何重复的 discount
属性值。
WITH DISTINCT
删除重复值MATCH (c:Customer)
WITH DISTINCT c.discount AS discountRates
RETURN discountRates
ORDER BY discountRates
discountRates |
---|
|
|
|
|
|
行数:5 |
排序和分页
WITH
可以与 ORDER BY
、LIMIT
和 SKIP
子句一起使用,以对结果进行排序和分页。如果这样使用,这些子句应被理解为 WITH
执行的结果操作的一部分——而不是独立的子句——在结果传递给后续子句之前。
在下面的查询中,结果首先使用 ORDER BY
按 Customer
消费最多的降序排序,然后才传递给最终的 RETURN
子句。
ORDER BY
排序结果MATCH (c:Customer)-[:BUYS]->(p:Product)
WITH c,
sum(p.price) AS totalSpent
ORDER BY totalSpent DESC
RETURN c.firstName AS customer, totalSpent
customer | totalSpent |
---|---|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
行数:7 |
在下一个示例中,LIMIT
用于在排序后仅保留结果集中 totalSpent
值最高的 3 个客户。然后,SET
为这些消费最多的客户分配一个新属性(topSpender = true
)。
LIMIT
限制结果MATCH (c:Customer)-[:BUYS]->(p:Product)
WITH c,
sum(p.price) AS totalSpent
ORDER BY totalSpent DESC
LIMIT 3
SET c.topSpender = true
RETURN c.firstName AS customer,
totalSpent,
c.topSpender AS topSpender
customer | totalSpent | topSpender |
---|---|---|
|
|
|
|
|
|
|
|
|
行数:3 |
SKIP
可以在 WITH
子句之后使用,以从结果集中丢弃行。下面,SKIP
排除排序结果集中的前 3 行(即 totalSpent
值最高的 3 个 Customer
节点),并为剩余 Customer
节点的新 topSpender
属性分配一个 false
值。
SKIP
排除结果MATCH (c:Customer)-[:BUYS]->(p:Product)
WITH c,
sum(p.price) AS totalSpent
ORDER BY totalSpent DESC
SKIP 3
SET c.topSpender = false
RETURN c.firstName AS customer,
totalSpent,
c.topSpender AS topSpender
customer | totalSpent | topSpender |
---|---|---|
|
|
|
|
|
|
|
|
|
|
|
|
行数:4 |
ORDER BY
、LIMIT
和 SKIP
也可以在 WITH
子句之后使用,以在继续进行进一步模式匹配之前缩小行集。在下面的查询中,首先匹配 Foodies Inc.
提供的所有产品。WITH
将这些产品传递出去,ORDER BY
按降序 price
对它们进行排序,LIMIT
只保留最昂贵的一个。然后第二个 MATCH
子句只从该单个产品中匹配,以找到所有购买它的客户。
MATCH (:Supplier {name: 'Foodies Inc.'})-[:SUPPLIES]->(p:Product)
WITH p
ORDER BY p.price DESC
LIMIT 1
MATCH (p)<-[:BUYS]-(c:Customer)
RETURN p.name AS product,
p.price AS price,
collect(c.firstName) AS customers
product | price | customers |
---|---|---|
|
|
|
行数:1 |
过滤结果
WITH
和 WHERE
过滤UNWIND [1, 2, 3, 4, 5, 6] AS x
WITH x
WHERE x > 2
RETURN x
x |
---|
|
|
|
|
行数:4 |
在下面的查询中,WITH
和 WHERE
用于过滤掉任何 totalSales
小于 1000
的 Supplier
节点。请注意在 collect()
中使用 DISTINCT
来删除任何重复的 Customer
节点。
WITH
和 WHERE
过滤属性值MATCH (s:Supplier)-[:SUPPLIES]->(p:Product)<-[:BUYS]-(c:Customer)
WITH s,
sum(p.price) AS totalSales,
count(DISTINCT c) AS uniqueCustomers
WHERE totalSales > 1000
RETURN s.name AS supplier,
totalSales,
uniqueCustomers
supplier | totalSales | uniqueCustomers |
---|---|---|
|
|
|
行数:1 |
组合写入和读取子句
如果写入子句后跟读取子句,则必须使用 WITH
作为两者之间的分隔符。
WITH
用作写入子句和读取子句之间的分隔符MATCH (yusuf:Customer {firstName: 'Yusuf'}),
(coffee:Product {name: 'Coffee'}),
(headphones:Product {name: 'Headphones'})
CREATE (yusuf)-[:BUYS {date: date('2025-04-15')}]->(coffee),
(yusuf)-[:BUYS {date: date('2025-04-15')}]->(headphones)
WITH yusuf
MATCH (yusuf)-[r:BUYS]->(p:Product)
RETURN collect(p.name) AS yusufPurchases,
r.date AS date
ORDER BY date DESC
yusufPurchases | date |
---|---|
|
|
|
|
|
|
行数:3 |