OPTIONAL MATCH 句直後のWHERE句の意味は?
Neo4jのcypher文の話です。例えば、つぎのようなテストデータがあったとします。
// create data
WITH RANGE(1,5) AS ages
UNWIND ages AS age CREATE(k:Kid{age:age}) RETURN k
;
MATCH(ks:Kid) WHERE ks.age > 2
WITH COLLECT(ks) AS ks
UNWIND ks AS k
FOREACH (n IN RANGE(1, k.age) | CREATE(k)-[:HAS]->(t:Toy{size:n}))
;
// show all data
MATCH(k:Kid)
OPTIONAL MATCH(k:Kid)-[:HAS]->(t:Toy) RETURN *;
// delete all data
MATCH(k:Kid)
OPTIONAL MATCH(k:Kid)-[:HAS]->(t:Toy) DETACH DELETE k, t RETURN *;
テストデータに対して、以下のような3つのクエリを投げてみる。
MATCH(k:Kid) // query No.1
WITH k
OPTIONAL MATCH(k:Kid)-[:HAS]->(t:Toy) WHERE t.size = 4
WITH k
WHERE t.size = 4
RETURN COUNT(DISTINCT k);
=> 2件
MATCH(k:Kid) // query No.2
WITH k
OPTIONAL MATCH(k:Kid)-[:HAS]->(t:Toy) WHERE t.size IS NOT NULL
WITH k
WHERE t.size IS NOT NULL
RETURN COUNT(DISTINCT k);
=> 3件
MATCH(k:Kid) // query No.3
WITH k
OPTIONAL MATCH(k:Kid)-[:HAS]->(t:Toy) WHERE t.size IS NULL
WITH k
WHERE t.size IS NULL
RETURN COUNT(DISTINCT k);
=> 5件
上記の結果について、No.1とNo.2については問題ない(予想通りの結果である)が、No.3は5件ではなく2件が正しいのではないかとずっと訝っていた。
なぜ5件になるかの理由が分からないのでStackoverflowに質問してみた。
そこで分かったことを以下に記す。
まず、大前提。
・OPTIONAL MATCHは全てのKidノードを返却する。
そして、
・WHERE句にマッチするToyノードはそのノードを、そうでなければnullを返却する。
以下は、想定通り。
MATCH(k:Kid) // query No.1
WITH k
OPTIONAL MATCH(k:Kid)-[:HAS]->(t:Toy) WHERE t.size = 4
RETURN k.age, t.size;
⇒
k.age t.size
1 null
2 null
3 null
4 4
5 4
では、以下は?
MATCH(k:Kid) // query No.1
WITH k
OPTIONAL MATCH(k:Kid)-[:HAS]->(t:Toy) WHERE t.size IS NULL
RETURN k.age, t.size;
⇒
k.age t.size
1 null // 実際にt.sizeがnullのもの
2 null // 同上
3 null // t.sizeはnullではないが、WHERE句にマッチしないので、nullが返されている
4 null // 同上
5 null // 同上
要するに、上記のように、同じnullでも2つの種類(意味合いの違い)があるということです。
この記事へのコメントはありません。