共用方式為


子查詢 - Cosmos DB 中的查詢語言 (在 Azure 和 Fabric 中)

子查詢是巢狀在查詢語言內另一個查詢中的查詢。 子查詢也稱為 內部查詢內部 SELECT查詢。 包含子查詢的陳述式通常稱為 外部查詢

子查詢的類型

子查詢主要有兩種類型:

  • 相關:參考外部查詢值的子查詢。 針對外部查詢處理的每一列,都會評估一次子查詢。
  • 非相關:獨立於外部查詢的子查詢。 它可以自行運行,而不依賴外部查詢。

子查詢可以根據它們傳回的列數和直欄數進一步分類。 有三種:

  • 表格:傳回多列多列。
  • 多值:傳回多列和單列。
  • 純量:傳回單一資料列和單一資料行。

查詢語言中的查詢一律會傳回單一資料行 (簡單值或複雜項目)。 因此,只有多值和純量子查詢才適用。 您只能在子句中使用 FROM 多值子查詢作為關聯式運算式。 您可以使用純量子查詢作為 or WHERE 子句中的SELECT純量表示式,或作為子句中的FROM關聯式表示式。

多值子查詢

多值子查詢會傳回一組項目,而且一律會在子句內 FROM 使用。 它們用於:

  • 最佳化 JOIN (自聯結) 運算式。
  • 評估一次昂貴的運算式並多次引用。

最佳化自聯結運算式

多值子查詢可以透過在每個選取多運算式之後推送述詞來最佳化JOIN運算式,而不是在子句中的所有WHERE交叉聯結之後推送述詞。

請考慮下列查詢:

SELECT VALUE
  COUNT(1)
FROM
  products p
JOIN 
  t in p.tags
JOIN
  s in p.sizes
JOIN
  c in p.colors
WHERE
  t.key IN ("fabric", "material") AND
  s["order"] >= 3 AND
  c LIKE "%gray%"

對於此查詢,索引會比對具有 或 keyfabricmaterial標籤的任何項目,至少一個大小order值大於 *three ,以及至少一個顏色 作為gray子字串。 這裡的JOIN運算式會在套用任何篩選器之前,針對每個相符項目執行 、 sizescolors陣列的所有tags項目的叉積

然後,該 WHERE 子句將過濾器述詞應用於每個 $<c、t、n、s>$ 元組。 例如,如果一個匹配的項目在三個陣列中的每一個中都有 十個 項目,則它會使用以下公式擴展到 1,000 個元組:

$$1 x 10 x 10 x 10$$

在這裡使用子查詢可以幫助在與下一個表達式聯結之前過濾掉聯結的陣列項目。

此查詢相當於前一個查詢,但使用子查詢:

SELECT VALUE
  COUNT(1)
FROM
  products p
JOIN 
  (SELECT VALUE t FROM t IN p.tags WHERE t.key IN ("fabric", "material"))
JOIN 
  (SELECT VALUE s FROM s IN p.sizes WHERE s["order"] >= 3)
JOIN 
  (SELECT VALUE c FROM c in p.colors WHERE c LIKE "%gray%")

假設標籤陣列中只有一個項目符合篩選條件,且數量和庫存陣列都有五個項目。 JOIN然後,運算式會使用此公式擴充至 25 個元組,而不是第一個查詢中的 1,000 個專案:

$$1 x 1 x 5 x 5$$

一次評估,多次參考

子查詢可以幫助優化具有昂貴表達式的查詢,例如使用者定義函數 (UDF)、複雜字串或算術表達式。 您可以將子查詢與 JOIN 運算式搭配使用,以評估運算式一次,但會參考它多次。

此範例查詢會計算價格,並在查詢中補充 25 次% 倍數。

SELECT VALUE {
  subtotal: p.price,
  total: (p.price * 1.25)
}
FROM
  products p
WHERE
  (p.price * 1.25) < 22.25

以下是只執行計算一次的對等查詢:

SELECT VALUE {
  subtotal: p.price,
  total: totalPrice
}
FROM
  products p
JOIN
  (SELECT VALUE p.price * 1.25) totalPrice
WHERE
  totalPrice < 22.25
[
  {
    "subtotal": 15,
    "total": 18.75
  },
  {
    "subtotal": 10,
    "total": 12.5
  },
  ...
]

小提示

請記住運算式的 JOIN 跨乘積行為。 如果運算式可以評估為 undefined,您應該確保 JOIN 運算式一律會從子查詢傳回物件,而不是直接傳回值來產生單一資料列。

模擬具有外部參考資料的關聯式聯結

您可能經常需要參考很少變更的靜態資料,例如 測量單位。 最好不要複製查詢中每個項目的靜態資料。 避免這種重複可以節省儲存空間,並透過保持較小的單一項目大小來改善寫入效能。 您可以使用子查詢來模擬具有靜態參考資料集合的內部聯結語意。

例如,考慮這組代表衣服長度的測量值:

大小 長度 單位
xs 63.5 cm
s 64.5 cm
m 66.0 cm
l 67.5 cm
xl 69.0 cm
xxl 70.5 cm

下列查詢會模擬與此資料的聯結,以便將單位名稱新增至輸出:

SELECT
  p.name,
  p.subCategory,
  s.description AS size,
  m.length,
  m.unit
FROM
  products p
JOIN
  s IN p.sizes
JOIN m IN (
  SELECT VALUE [
    {size: 'xs', length: 63.5, unit: 'cm'},
    {size: 's', length: 64.5, unit: 'cm'},
    {size: 'm', length: 66, unit: 'cm'},
    {size: 'l', length: 67.5, unit: 'cm'},
    {size: 'xl', length: 69, unit: 'cm'},
    {size: 'xxl', length: 70.5, unit: 'cm'}
  ]
)
WHERE
  s.key = m.size

純量子查詢

純量子查詢運算式是評估為單一值的子查詢。 純量子查詢表達式的值是子查詢的投影(SELECT 子句)的值。 您可以在純量表示式有效的許多位置使用純量子查詢表示式。 例如,您可以在 和 SELECTWHERE 子句中的任何運算式中使用純量子查詢。

使用純量子查詢並不總是有助於優化您的查詢。 例如,將純量子查詢作為引數傳遞至系統或使用者定義函式,在減少資源單位 (RU) 耗用量或延遲方面沒有任何好處。

純量子查詢可以進一步分類為:

  • 簡單運算式純量子查詢
  • 彙總純量子查詢

簡單運算式純量子查詢

簡單運算式純量子查詢是相互關聯的子查詢,其子句不 SELECT 包含任何彙總運算式。 這些子查詢不提供最佳化優點,因為編譯器會將它們轉換成一個較大的簡單運算式。 內部和外部查詢之間沒有相互關聯的內容。

作為第一個範例,請考慮這個簡單的查詢。

SELECT
  1 AS a,
  2 AS b

您可以使用簡單運算式純量子查詢來重寫此查詢。

SELECT
  (SELECT VALUE 1) AS a, 
  (SELECT VALUE 2) AS b

這兩個查詢都會產生相同的輸出。

[
  {
    "a": 1,
    "b": 2
  }
]

下一個範例查詢會將唯一識別碼與前置詞串連為簡單運算式純量子查詢。

SELECT 
  (SELECT VALUE CONCAT('ID-', p.id)) AS internalId
FROM
  products p

此範例使用簡單運算式純量子查詢,僅傳回每個項目的相關欄位。 查詢會針對每個專案輸出一些內容,但只有在符合子查詢內的篩選條件時,它才會包含投影欄位。

SELECT
  p.id,
  (SELECT p.name WHERE CONTAINS(p.name, "Shoes")).name
FROM
  products p
[
  {
    "id": "00000000-0000-0000-0000-000000004041",
    "name": "Remdriel Shoes"
  },
  {
    "id": "00000000-0000-0000-0000-000000004322"
  },
  {
    "id": "00000000-0000-0000-0000-000000004055"
  }
]

彙總純量子查詢

彙總純量子查詢是子查詢,其投影或篩選器中具有彙總函數,可評估為單一值。

作為第一個範例,請考慮具有下列欄位的專案。

[
  {
    "name": "Blators Snowboard Boots",
    "colors": [
      "turquoise",
      "cobalt",
      "jam",
      "galliano",
      "violet"
    ],
    "sizes": [ ... ],
    "tags": [ ... ]
  }
]

這是一個子查詢,其投影中具有單一聚合函數運算式。 此查詢會計算每個項目的所有標籤。

SELECT
  p.name,
  (SELECT VALUE COUNT(1) FROM c IN p.colors) AS colorsCount
FROM
  products p
WHERE
  p.id = "00000000-0000-0000-0000-000000004389"
[
  {
    "name": "Blators Snowboard Boots",
    "colorsCount": 5
  }
]

這是具有篩選器的相同子查詢。

SELECT
  p.name,
  (SELECT VALUE COUNT(1) FROM c IN p.colors) AS colorsCount,
  (SELECT VALUE COUNT(1) FROM c IN p.colors WHERE c LIKE "%t") AS colorsEndsWithTCount
FROM
  products p
[
  {
    "name": "Blators Snowboard Boots",
    "colorsCount": 5,
    "colorsEndsWithTCount": 2
  }
]

這是另一個具有多個聚合函數表達式的子查詢:

SELECT
  p.name,
  (SELECT VALUE COUNT(1) FROM c IN p.colors) AS colorsCount,
  (SELECT VALUE COUNT(1) FROM s in p.sizes) AS sizesCount,
  (SELECT VALUE COUNT(1) FROM t IN p.tags) AS tagsCount
FROM
  products p
[
  {
    "name": "Blators Snowboard Boots",
    "colorsCount": 5,
    "sizesCount": 7,
    "tagsCount": 2
  }
]

最後,這是一個在投影和篩選器中都有彙總子查詢的查詢:

SELECT
  p.name,
  (SELECT VALUE COUNT(1) FROM s in p.sizes WHERE s.description LIKE "%Small") AS smallSizesCount,
  (SELECT VALUE COUNT(1) FROM s in p.sizes WHERE s.description LIKE "%Large") AS largeSizesCount
FROM
  products p
WHERE
  (SELECT VALUE COUNT(1) FROM c IN p.colors) >= 5

撰寫此查詢的最佳方式是在子查詢上聯結,並在 SELECT 和 WHERE 子句中參考子查詢別名。 此查詢更有效率,因為您只需要在聯結陳述式內執行子查詢,而不需要在投影和篩選器中執行子查詢。

SELECT
  p.name,
  colorCount,
  smallSizesCount,
  largeSizesCount
FROM
  products p
JOIN
  (SELECT VALUE COUNT(1) FROM c IN p.colors) AS colorCount
JOIN
  (SELECT VALUE COUNT(1) FROM s in p.sizes WHERE s.description LIKE "%Small") AS smallSizesCount
JOIN
  (SELECT VALUE COUNT(1) FROM s in p.sizes WHERE s.description LIKE "%Large") AS largeSizesCount
WHERE
  colorCount >= 5 AND
  largeSizesCount > 0 AND
  smallSizesCount > 0

EXISTS 運算式

查詢語言支援 EXISTS 運算式。 此運算式是內建於查詢語言中的彙總純量子查詢。 EXISTS 採用子查詢運算式,並在子查詢傳回任何資料列時傳回 true 。 否則,它會傳回 false

由於查詢引擎不會區分布林運算式和任何其他純量運算式,因此您可以同時SELECT使用 EXISTS and WHERE 子句。 此行為與 T-SQL 不同,其中布林運算式僅限於篩選。

如果子查詢傳回單一值,undefinedEXISTS評估為 falseEXISTS。 例如,請考慮下列查詢,該查詢不傳回任何內容。

SELECT VALUE
  undefined

如果您使用 EXISTS 運算式和先前的查詢作為子查詢,則運算式會傳回 false

SELECT VALUE
  EXISTS (SELECT VALUE undefined)
[
  false
]

如果省略上述子查詢中的 VALUE 關鍵字,則子查詢會評估為具有單一空白物件的陣列。

SELECT
  undefined
[
  {}
]

此時, EXISTS 運算式的計算結果為 , true 因為物件 ({}) 在技術上已結束。

SELECT VALUE
  EXISTS (SELECT undefined)
[
  true
]

ARRAY_CONTAINS 常見使用案例是依陣列中是否存在專案來篩選專案。 在這種情況下,我們正在檢查陣列是否tags包含名為「outerwear」的項目。

SELECT
  p.name,
  p.colors
FROM
  products p
WHERE
  ARRAY_CONTAINS(p.colors, "cobalt")

相同的查詢可以用作 EXISTS 替代選項。

SELECT
  p.name,
  p.colors
FROM
  products p
WHERE
  EXISTS (SELECT VALUE c FROM c IN p.colors WHERE c = "cobalt")

此外, ARRAY_CONTAINS 只能檢查值是否等於陣列中的任何元素。 如果您需要陣列屬性上更複雜的篩選器,請改用 JOIN

考慮一個集合中的這個範例項目,其中有多個項目,每個項目都包含一個 accessories 陣列。

[
  {
    "name": "Cosmoxy Pack",
    "tags": [
      {
        "key": "fabric",
        "value": "leather",
        "description": "Leather"
      },
      {
        "key": "volume",
        "value": "68-gal",
        "description": "6.8 Gal"
      }
    ]
  }
]

現在,請考慮下列查詢,該查詢會根據每個專案內陣列中的 和 typequantityOnHand 屬性進行篩選。

SELECT
  p.name,
  t.description AS tag
FROM
  products p
JOIN
  t in p.tags
WHERE
  t.key = "fabric" AND
  t["value"] = "leather"
[
  {
    "name": "Cosmoxy Pack",
    "tag": "Leather"
  }
]

對於集合中的每個項目,會使用其陣列元素執行叉積。 此 JOIN 作業可讓您篩選陣列內的屬性。 不過,此查詢的 RU 耗用量很重要。 例如,如果 1,000 個項目的每個陣列中有 100 個項目,則使用以下公式將其擴展為 100,000 個元組:

$$1,000 x 100$$

使用 EXISTS 有助於避免這種昂貴的交叉乘積。 在下一個範例中,查詢會篩選子查詢內的 EXISTS 陣列元素。 如果陣列元素符合篩選器,則您可以投影它並 EXISTS 評估為 true。

SELECT VALUE
  p.name
FROM
  products p
WHERE
  EXISTS (
    SELECT VALUE
      t
    FROM
      t IN p.tags
    WHERE
      t.key = "fabric" AND
      t["value"] = "leather"
  )
[
  "Cosmoxy Pack"
]

查詢也允許在投影中進行別名 EXISTS 和參照別名:

SELECT
  p.name,
  EXISTS (
    SELECT VALUE
      t
    FROM
      t IN p.tags
    WHERE
      t.key = "fabric" AND
      t["value"] = "leather"
  ) AS containsFabricLeatherTag
FROM
  products p
[
  {
    "name": "Cosmoxy Pack",
    "containsFabricLeatherTag": true
  }
]

ARRAY 運算式

您可以使用運算式將 ARRAY 查詢的結果投影為陣列。 您只能在查詢的子句內 SELECT 使用此運算式。

對於這些範例,假設有一個至少包含此專案的容器。

[
  {
    "name": "Menti Sandals",
    "sizes": [
      {
        "key": "5"
      },
      {
        "key": "6"
      },
      {
        "key": "7"
      },
      {
        "key": "8"
      },
      {
        "key": "9"
      }
    ]
  }
]

在第一個範例中,運算式會使用在子句內 SELECT

SELECT
  p.name,
  ARRAY (
    SELECT VALUE
      s.key
    FROM
      s IN p.sizes
  ) AS sizes
FROM
  products p
WHERE
  p.name = "Menti Sandals"
[
  {
    "name": "Menti Sandals",
    "sizes": [
      "5",
      "6",
      "7",
      "8",
      "9"
    ]
  }
]

與其他子查詢一樣,可以使用運算式進行 ARRAY 篩選。

SELECT
  p.name,
  ARRAY (
    SELECT VALUE
      s.key
    FROM
      s IN p.sizes
    WHERE
      STRINGTONUMBER(s.key) <= 6
  ) AS smallSizes,
  ARRAY (
    SELECT VALUE
      s.key
    FROM
      s IN p.sizes
    WHERE
      STRINGTONUMBER(s.key) >= 9
  ) AS largeSizes
FROM
  products p
WHERE
  p.name = "Menti Sandals"
[
  {
    "name": "Menti Sandals",
    "smallSizes": [
      "5",
      "6"
    ],
    "largeSizes": [
      "9"
    ]
  }
]

陣列運算式也可以位於子查詢中的子句之後 FROM

SELECT
  p.name,
  z.s.key AS sizes
FROM
  products p
JOIN
  z IN (
    SELECT VALUE
      ARRAY (
        SELECT
          s
        FROM
          s IN p.sizes
        WHERE
          STRINGTONUMBER(s.key) <= 8
      )
  )
[
  {
    "name": "Menti Sandals",
    "sizes": "5"
  },
  {
    "name": "Menti Sandals",
    "sizes": "6"
  },
  {
    "name": "Menti Sandals",
    "sizes": "7"
  },
  {
    "name": "Menti Sandals",
    "sizes": "8"
  }
]