Couchbase中的LEFT OUTER JOIN + WHERE子句

时间:2017-01-10 21:53:24

标签: couchbase n1ql

我尝试在联接的右侧部分进行过滤时执行LEFT OUTER JOIN

我创建了以下索引来实现此目的:

CREATE INDEX `idx_store_order` ON `myBucket`(("Store::" || `storeId`)) WHERE ((`docType` = "Order") or (`docType` is missing))

我试图执行以下查询:

SELECT store.status, order.clientId, store.docId 
FROM myBucket store
LEFT OUTER JOIN myBucket order ON KEY ("Store::" || order.storeId) FOR store
WHERE store.docType="Store"
AND (order.docType="Order" OR order.docType IS MISSING)
AND order.clientId="9281ae36-a418-4ea3-93f0-bfd7b1a38248"

我有30个带docType="Store"的文档,但是当我执行此查询时,我没有得到30个结果。如果我删除最后一个子句并逐个存储,那么我得到30个结果,所以这是影响最终结果的最后一个子句。

我还尝试了以下语句(不成功)作为最后一句:

(AND order.clientId="9281ae36-a418-4ea3-93f0-bfd7b1a38248" OR order.docType IS MISSING)

我错过了什么吗?感谢

修改 这是解释查询:

[
  {
    "plan": {
      "#operator": "Sequence",
      "~children": [
        {
          "#operator": "IndexScan",
          "index": "idx_docType",
          "index_id": "e498d0c0ee2f0d9d",
          "keyspace": "myBucket",
          "namespace": "default",
          "spans": [
            {
              "Range": {
                "High": [
                  "\"Store\""
                ],
                "Inclusion": 3,
                "Low": [
                  "\"Store\""
                ]
              }
            }
          ],
          "using": "gsi"
        },
        {
          "#operator": "Parallel",
          "~child": {
            "#operator": "Sequence",
            "~children": [
              {
                "#operator": "Fetch",
                "as": "store",
                "keyspace": "myBucket",
                "namespace": "default"
              },
              {
                "#operator": "IndexJoin",
                "as": "order",
                "for": "store",
                "keyspace": "myBucket",
                "namespace": "default",
                "on_key": "(\"Store::\" || (`order`.`storeId`))",
                "outer": true,
                "scan": {
                  "index": "idx_store_order",
                  "index_id": "a97fce5158e6e573",
                  "using": "gsi"
                }
              },
              {
                "#operator": "Filter",
                "condition": "((((`store`.`docType`) = \"Store\") and (((`order`.`docType`) = \"Order\") or ((`order`.`docType`) is missing))) and (((`order`.`clientId`) = \"9281ae36-a418-4ea3-93f0-bfd7b1a138248\") or (`order` is missing)))"
              },
              {
                "#operator": "InitialProject",
                "result_terms": [
                  {
                    "expr": "(`store`.`status`)"
                  }
                ]
              },
              {
                "#operator": "FinalProject"
              }
            ]
          }
        }
      ]
    },
    "text": "SELECT store.status\nFROM myBucket store\nLEFT OUTER JOIN myBucket order ON KEY (\"Store::\" || order.storeId) FOR store\nWHERE store.docType=\"Store\"\nAND (order.docType=\"Order\" OR order.docType IS MISSING)\nAND (order.clientId=\"9281ae36-a418-4ea3-93f0-bfd7b1a138248\" OR order IS MISSING)"
  }
]

EDIT2

正如评论中所讨论的,我想列出所有商店,无论给定客户是否有订单。如果客户确实有订单,那么我想显示某些字段以及商店列表。

E.g。 商店1 - 客户X没有订单 商店2 - 客户X确实有一个订单,并且商店信息中显示了一些信息

2 个答案:

答案 0 :(得分:1)

外连接产生所有左侧文档,而不管是否成功匹配连接键谓词(而不是where子句中的任何条件)。这意味着,无论您是否匹配order.storeId,都可获得30个结果。

在这种情况下,最后一个过滤器是在客户端ID上,它在JOIN之后应用,因此正在过滤一些文档。检查/发布EXPLAIN输出以进行验证。

答案 1 :(得分:0)

在当前的N1QL中,WHERE子句不被视为JOIN谓词的一部分,因此您必须执行以下操作。您需要始终逃避订单,或使用其他别名。

SELECT store.status, order.userId, store.docId 
FROM myBucket store
LEFT OUTER JOIN myBucket order ON KEY ("Store::" || order.storeId) FOR store
WHERE store.docType="Store"
AND (
(order IS MISSING)
OR
 ((order.docType="Order" OR order.docType IS MISSING)
AND order.clientId="9281ae36-a418-4ea3-93f0-bfd7b1a38248")