跳到主要内容
版本:3.11.0

WHERE

WHERE子句可以根据条件过滤输出结果。

WHERE子句通常用于如下查询:

  • 原生 nGQL,例如GOLOOKUP语句。

  • openCypher 方式,例如MATCHWITH语句。

openCypher 兼容性

过滤 Rank 是原生 nGQL 功能。如需在 openCypher 兼容语句中直接获取 Rank 值,可以使用 rank() 函数,例如MATCH (:player)-[e:follow]->() RETURN rank(e);

基础用法

备注

下文示例中的$$$^等是引用符号,详情请参见引用符

用布尔运算符定义条件

WHERE子句中使用布尔运算符NOTANDORXOR定义条件。关于运算符的优先级,请参见运算符优先级

nebula> MATCH (v:player) \
WHERE v.player.name == "Tim Duncan" \
XOR (v.player.age < 30 AND v.player.name == "Yao Ming") \
OR NOT (v.player.name == "Yao Ming" OR v.player.name == "Tim Duncan") \
RETURN v.player.name, v.player.age;
+-------------------------+--------------+
| v.player.name | v.player.age |
+-------------------------+--------------+
| "Danny Green" | 31 |
| "Tiago Splitter" | 34 |
| "David West" | 38 |
...
nebula> GO FROM "player100" \
OVER follow \
WHERE properties(edge).degree > 90 \
OR properties($$).age != 33 \
AND properties($$).name != "Tony Parker" \
YIELD properties($$);
+----------------------------------+
| properties($$) |
+----------------------------------+
| {age: 41, name: "Manu Ginobili"} |
+----------------------------------+

过滤属性

WHERE子句中使用点或边的属性定义条件。

  • 过滤点属性:

    nebula> MATCH (v:player)-[e]->(v2) \
    WHERE v2.player.age < 25 \
    RETURN v2.player.name, v2.player.age;
    +----------------------+---------------+
    | v2.player.name | v2.player.age |
    +----------------------+---------------+
    | "Ben Simmons" | 22 |
    | "Luka Doncic" | 20 |
    | "Kristaps Porzingis" | 23 |
    +----------------------+---------------+
    nebula> GO FROM "player100" OVER follow \
    WHERE $^.player.age >= 42 \
    YIELD dst(edge);
    +-------------+
    | dst(EDGE) |
    +-------------+
    | "player101" |
    | "player125" |
    +-------------+
  • 过滤边属性:

    nebula> MATCH (v:player)-[e]->() \
    WHERE e.start_year < 2000 \
    RETURN DISTINCT v.player.name, v.player.age;
    +--------------------+--------------+
    | v.player.name | v.player.age |
    +--------------------+--------------+
    | "Tony Parker" | 36 |
    | "Tim Duncan" | 42 |
    | "Grant Hill" | 46 |
    ...
    nebula> GO FROM "player100" OVER follow \
    WHERE follow.degree > 90 \
    YIELD dst(edge);
    +-------------+
    | dst(EDGE) |
    +-------------+
    | "player101" |
    | "player125" |
    +-------------+

过滤动态计算属性

nebula> MATCH (v:player) \
WHERE v[toLower("AGE")] < 21 \
RETURN v.player.name, v.player.age;
+---------------+-------+
| v.name | v.age |
+---------------+-------+
| "Luka Doncic" | 20 |
+---------------+-------+

过滤现存属性

nebula> MATCH (v:player) \
WHERE exists(v.player.age) \
RETURN v.player.name, v.player.age;
+-------------------------+--------------+
| v.player.name | v.player.age |
+-------------------------+--------------+
| "Danny Green" | 31 |
| "Tiago Splitter" | 34 |
| "David West" | 38 |
...

过滤 rank

在 nGQL 中,如果多个边拥有相同的起始点、目的点和属性,则它们的唯一区别是 rank 值。在WHERE子句中可以使用 rank 过滤边。

# 创建测试数据。
nebula> CREATE SPACE IF NOT EXISTS test (vid_type=FIXED_STRING(30));
nebula> USE test;
nebula> CREATE EDGE IF NOT EXISTS e1(p1 int);
nebula> CREATE TAG IF NOT EXISTS person(p1 int);
nebula> INSERT VERTEX person(p1) VALUES "1":(1);
nebula> INSERT VERTEX person(p1) VALUES "2":(2);
nebula> INSERT EDGE e1(p1) VALUES "1"->"2"@0:(10);
nebula> INSERT EDGE e1(p1) VALUES "1"->"2"@1:(11);
nebula> INSERT EDGE e1(p1) VALUES "1"->"2"@2:(12);
nebula> INSERT EDGE e1(p1) VALUES "1"->"2"@3:(13);
nebula> INSERT EDGE e1(p1) VALUES "1"->"2"@4:(14);
nebula> INSERT EDGE e1(p1) VALUES "1"->"2"@5:(15);
nebula> INSERT EDGE e1(p1) VALUES "1"->"2"@6:(16);

# 通过 rank 过滤边,查找 rank 大于 2 的边。
nebula> GO FROM "1" \
OVER e1 \
WHERE rank(edge) > 2 \
YIELD src(edge), dst(edge), rank(edge) AS Rank, properties(edge).p1 | \
ORDER BY $-.Rank DESC;
+-----------+-----------+------+---------------------+
| src(EDGE) | dst(EDGE) | Rank | properties(EDGE).p1 |
+-----------+-----------+------+---------------------+
| "1" | "2" | 6 | 16 |
| "1" | "2" | 5 | 15 |
| "1" | "2" | 4 | 14 |
| "1" | "2" | 3 | 13 |
+-----------+-----------+------+---------------------+

# 通过 rank 过滤边,查找 rank 值等于 0 的 follow 边。
nebula> MATCH (v)-[e:follow]->() \
WHERE rank(e)==0 \
RETURN *;
+------------------------------------------------------------+-----------------------------------------------------+
| v | e |
+------------------------------------------------------------+-----------------------------------------------------+
| ("player142" :player{age: 29, name: "Klay Thompson"}) | [:follow "player142"->"player117" @0 {degree: 90}] |
| ("player139" :player{age: 34, name: "Marc Gasol"}) | [:follow "player139"->"player138" @0 {degree: 99}] |
| ("player108" :player{age: 36, name: "Boris Diaw"}) | [:follow "player108"->"player100" @0 {degree: 80}] |
| ("player108" :player{age: 36, name: "Boris Diaw"}) | [:follow "player108"->"player101" @0 {degree: 80}] |
...

过滤 pattern

nebula> MATCH (v:player{name:"Tim Duncan"})-[e]->(t) \
WHERE (v)-[e]->(t:team) \
RETURN (v)-->();

+------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
| (v)-->() = (v)-->() |
+------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
| [<("player100" :player{age: 42, name: "Tim Duncan"})-[:serve@0 {end_year: 2016, start_year: 1997}]->("team204" :team{name: "Spurs"})>, <("player100" :player{age: 42, name: "Tim Duncan"})-[:follow@0 {degree: 95}]->("player101" :player{age: 36, name: "Tony Parker"})>, <("player100" :player{age: 42, name: "Tim Duncan"})-[:follow@0 {degree: 95}]->("player125" :player{age: 41, name: "Manu Ginobili"})>] |
+------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+

nebula> MATCH (v:player{name:"Tim Duncan"})-[e]->(t) \
WHERE NOT (v)-[e]->(t:team) \
RETURN (v)-->();
+------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
| (v)-->() = (v)-->() |
+------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
| [<("player100" :player{age: 42, name: "Tim Duncan"})-[:serve@0 {end_year: 2016, start_year: 1997}]->("team204" :team{name: "Spurs"})>, <("player100" :player{age: 42, name: "Tim Duncan"})-[:follow@0 {degree: 95}]->("player101" :player{age: 36, name: "Tony Parker"})>, <("player100" :player{age: 42, name: "Tim Duncan"})-[:follow@0 {degree: 95}]->("player125" :player{age: 41, name: "Manu Ginobili"})>] |
| [<("player100" :player{age: 42, name: "Tim Duncan"})-[:serve@0 {end_year: 2016, start_year: 1997}]->("team204" :team{name: "Spurs"})>, <("player100" :player{age: 42, name: "Tim Duncan"})-[:follow@0 {degree: 95}]->("player101" :player{age: 36, name: "Tony Parker"})>, <("player100" :player{age: 42, name: "Tim Duncan"})-[:follow@0 {degree: 95}]->("player125" :player{age: 41, name: "Manu Ginobili"})>] |
+------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+

过滤字符串

WHERE子句中使用STARTS WITHENDS WITHCONTAINS可以匹配字符串的特定部分。匹配时区分大小写。

STARTS WITH

STARTS WITH会从字符串的起始位置开始匹配。

# 查询姓名以 T 开头的 player 信息。
nebula> MATCH (v:player) \
WHERE v.player.name STARTS WITH "T" \
RETURN v.player.name, v.player.age;
+------------------+--------------+
| v.player.name | v.player.age |
+------------------+--------------+
| "Tony Parker" | 36 |
| "Tiago Splitter" | 34 |
| "Tim Duncan" | 42 |
| "Tracy McGrady" | 39 |
+------------------+--------------+

如果使用小写tSTARTS WITH "t"),会返回空集,因为数据库中没有以小写t开头的姓名。

nebula> MATCH (v:player) \
WHERE v.player.name STARTS WITH "t" \
RETURN v.player.name, v.player.age;
+---------------+--------------+
| v.player.name | v.player.age |
+---------------+--------------+
+---------------+--------------+
Empty set (time spent 5080/6474 us)

ENDS WITH

ENDS WITH会从字符串的结束位置开始匹配。

nebula> MATCH (v:player) \
WHERE v.player.name ENDS WITH "r" \
RETURN v.player.name, v.player.age;
+------------------+--------------+
| v.player.name | v.player.age |
+------------------+--------------+
| "Tony Parker" | 36 |
| "Tiago Splitter" | 34 |
| "Vince Carter" | 42 |
+------------------+--------------+

CONTAINS

CONTAINS会检查关键字是否匹配字符串的某一部分。

nebula> MATCH (v:player) \
WHERE v.player.name CONTAINS "Pa" \
RETURN v.player.name, v.player.age;
+---------------+--------------+
| v.player.name | v.player.age |
+---------------+--------------+
| "Paul George" | 28 |
| "Tony Parker" | 36 |
| "Paul Gasol" | 38 |
| "Chris Paul" | 33 |
+---------------+--------------+

结合 NOT 使用

用户可以结合布尔运算符NOT一起使用,否定字符串匹配条件。

nebula> MATCH (v:player) \
WHERE NOT v.player.name ENDS WITH "R" \
RETURN v.player.name, v.player.age;
+-------------------------+--------------+
| v.player.name | v.player.age |
+-------------------------+--------------+
| "Danny Green" | 31 |
| "Tiago Splitter" | 34 |
| "David West" | 38 |
| "Russell Westbrook" | 30 |
...

过滤列表

匹配列表中的值

使用IN运算符检查某个值是否在指定列表中。

nebula> MATCH (v:player) \
WHERE v.player.age IN range(20,25) \
RETURN v.player.name, v.player.age;
+-------------------------+--------------+
| v.player.name | v.player.age |
+-------------------------+--------------+
| "Ben Simmons" | 22 |
| "Giannis Antetokounmpo" | 24 |
| "Kyle Anderson" | 25 |
| "Joel Embiid" | 25 |
| "Kristaps Porzingis" | 23 |
| "Luka Doncic" | 20 |
+-------------------------+--------------+

nebula> LOOKUP ON player \
WHERE player.age IN [25,28] \
YIELD properties(vertex).name, properties(vertex).age;
+-------------------------+------------------------+
| properties(VERTEX).name | properties(VERTEX).age |
+-------------------------+------------------------+
| "Kyle Anderson" | 25 |
| "Damian Lillard" | 28 |
| "Joel Embiid" | 25 |
| "Paul George" | 28 |
| "Ricky Rubio" | 28 |
+-------------------------+------------------------+

结合 NOT 使用

nebula> MATCH (v:player) \
WHERE v.player.age NOT IN range(20,25) \
RETURN v.player.name AS Name, v.player.age AS Age \
ORDER BY Age;
+---------------------+-----+
| Name | Age |
+---------------------+-----+
| "Kyrie Irving" | 26 |
| "Cory Joseph" | 27 |
| "Damian Lillard" | 28 |
| "Paul George" | 28 |
| "Ricky Rubio" | 28 |
...