Python NDB/DB 適用的 GQL 參考資料

GQL 是類似 SQL 的語言,用於擷取實體和金鑰。GQL 查詢的語法與 SQL 相似。本頁提供參考資料,說明如何搭配使用 Python NDB 和 DB 用戶端程式庫使用 GQL。

GQL 大致對應至 SQL:您可以將 GQL kind 視為 SQL 資料表、GQL entity 視為 SQL 資料列,以及 GQL property 視為 SQL 欄。不過,SQL 的資料列-資料欄查詢為單一值,但 GQL 的屬性值可能是一份清單。

GQL 版本

根據執行查詢的位置,您會需要不同版本的 GQL。以下提供兩份 GQL 參考資料:

語法

以下摘要說明 Python NDB/DB 適用的 GQL 語法:

SELECT [DISTINCT] [* | <property list> | __key__]
  [FROM <kind>]
  [WHERE <condition> [AND <condition> ...]]
  [ORDER BY <property> [ASC | DESC] [, <property> [ASC | DESC] ...]]
  [LIMIT [<offset>,]<count>]
  [OFFSET <offset>]

  <property list> := <property> [, <property> ...]
  <condition> := <property> {< | <= | > | >= | = | != } <value>
  <condition> := <property> IN <list>
  <condition> := ANCESTOR IS <entity or key>
  <list> := (<value> [, <value> ...]])

和 SQL 一樣,GQL 關鍵字不區分大小寫。種類和屬性名稱需區分大小寫。

GQL 只支援 SELECT 陳述式。

GQL 查詢會傳回 0 個以上所要求種類的完整實體、投影實體金鑰。每項 GQL 查詢的開頭均為 SELECT *SELECT __key__ 或 SELECT <property list>,其中 property 是以半形逗號分隔的清單,當中包含查詢傳回的一或多項實體屬性。不過,GQL 查詢無法執行類似於 SQL 的「彙整」查詢。

提示: SELECT __key__ or SELECT <property list> 查詢速度較快,且使用的 CPU 時間較 SELECT * 查詢少。

選用的 DISTINCT(實驗版) 子句會指定只有完全不重複的結果能透過結果集傳回。如有多個實體的受限屬性包含相同的值,這種方式只會傳回第一個結果。

選用 FROM 子句會將結果集限制在特定種類的實體內。不含 FROM 子句的查詢稱為無類型查詢,且只能有指定 __key__ 屬性的 WHERE

選用 WHERE 子句會將結果集限制在符合一或多個條件的實體內。每個條件都會使用比較運算子將實體的屬性與值進行比較。如果使用 AND 關鍵字提供多個條件,實體必須符合所有條件,才能由查詢傳回。GQL 沒有 OR 運算子。不過,它確實有 IN 運算子,可提供 OR 的限制形式。

IN 運算子會將屬性的值與清單中的每個項目進行比較。IN 運算子等同於許多 = 查詢 (每個值一個),並以 OR 運算結合。如果實體中指定屬性的值等於清單中的任何值,查詢就會傳回該實體。

注意:IN!= 運算子會在背景使用多項查詢。舉例來說,IN 運算子會針對清單中的每個項目執行個別的基礎資料儲存庫查詢。傳回的實體是所有基礎資料儲存庫查詢的交叉乘積結果,並已排除重複項目。任何單一 GQL 查詢最多可以有 30 個資料儲存庫查詢。

條件也可以使用 ANCESTOR IS 運算子,測試實體是否具有特定實體做為祖系。值是祖系實體的模型例項或。如要進一步瞭解祖系,請參閱「鍵和實體群組」。

比較的左側一律是屬性名稱。屬性名稱通常會包含英數字元,也可以選擇包含底線和點。換句話說,這些值符合規則運算式 [a-zA-Z0-9_]+(\.[a-zA-Z0-9_]+)*

注意:包含其他可列印字元的屬性名稱必須以雙引號括住,例如:"first-name"。不支援屬性名稱中的空格或無法列印的字元。

比較的右側可以是下列其中一項 (根據屬性的資料類型而定):

  • str 常值,以單引號字串表示。字串中的單引號字元必須逸出為 ''。例如: 'Joe''s Diner'
  • 整數或浮點數常值。例如: 42.7
  • 布林常值,指 TRUEFALSE
  • NULL 字面值,代表空值 (在 Python 中為 None)。
  • 日期時間、日期或時間值常值,可使用數值或字串表示法,格式如下:
    • DATETIME(year, month, day, hour, minute, second)
    • DATETIME('YYYY-MM-DD HH:MM:SS')
    • DATE(year, month, day)
    • DATE('YYYY-MM-DD')
    • TIME(hour, minute, second)
    • TIME('HH:MM:SS')
  • 實體金鑰常值,包含以字串編碼的金鑰種類和金鑰名稱/ID 的完整路徑

    • KEY('encoded key')
    • KEY('kind', 'name'/ID [, 'kind', 'name'/ID...])
  • 使用者物件運算式,其中包含使用者的電子郵件地址:
    USER('email-address')
  • GeoPt 文字常值,其中緯度和經度為浮點值:
    GEOPT(lat, long)
  • 繫結參數值。在查詢字串中,位置參數會以數字參照:title = :1。關鍵字參數會以名稱參照:title = :mytitle

注意:格式為 property = NULL 的條件會確認空值是否明確儲存在該項屬性的資料儲存庫中。這與檢查實體是否缺少屬性值不同!資料儲存庫查詢參照屬性時,絕不會傳回沒有該屬性值的實體。

繫結參數可以繫結為位置引數或關鍵字引數,並傳送給 GqlQuery 建構函式或模型類別的 gql() 方法。屬性資料類型 (包括清單資料類型) 如沒有對應的值字面語法,就必須使用參數繫結指定。在 GqlQuery 執行個體的生命週期內 (例如有效率地重複使用查詢),參數繫結可以使用 bind() 方法與新值重新建立繫結。

選用的 ORDER BY 子句表示結果應以遞增 (ASC) 或遞減 (DESC) 順序,依指定屬性排序後傳回。ORDER BY 子句可將多個排序順序指定為以逗號分隔的清單,並從左到右進行評估。如未指定方向,則預設為 ASC。如果未指定 ORDER BY 子句,則結果的順序未定義,且可能會隨時間而變更。

選用的 LIMIT 子句會讓查詢在第一個 <count> 實體後停止傳回結果。LIMIT 子句也可以包含 <offset>,藉此略過多個結果,找出要傳回的第一個結果。如果沒有 LIMIT 子句,選用的 OFFSET 子句可以指定 <offset>

注意:如同 fetch() 方法的 offset 參數,GQL 查詢字串中的 OFFSET 不會減少從資料儲存庫擷取的實體數量。這只會影響 fetch() 方法傳回的結果。使用 offset 的查詢含有效能特性,可以隨著偏移大小和限制大小進行線性對應。

如要瞭解如何執行 GQL 查詢、繫結參數和存取結果,請參閱 GqlQuery 類別和 Model.gql() 類別方法。

範例

from google.appengine.ext import db

class Person(db.Model):
  name = db.StringProperty()
  age = db.IntegerProperty()

# We use a unique username for the Entity's key.
amy = Person(key_name='amym', name='Amy', age=48)
amy.put()
Person(key_name='bettyd', name='Betty', age=42).put()
Person(key_name='charliec', name='Charlie', age=32).put()
Person(key_name='charliek', name='Charlie', age=29).put()
Person(key_name='eedna', name='Edna', age=20).put()
Person(key_name='fredm', name='Fred', age=16, parent=amy).put()
Person(key_name='georgemichael', name='George').put()

如要找出年齡介於 18 到 35 歲的所有 Person 類型實體 (即 Charlies 和 Edna),請使用以下查詢:

SELECT * FROM Person WHERE age >= 18 AND age <= 35

如要找出年齡最大的三個 Person 類型實體 (即 Amy、Betty 和 Charlie),請使用以下查詢:

SELECT * FROM Person ORDER BY age DESC LIMIT 3

如要尋找名稱為「Betty」或「Charlie」的 Person 類型實體,請使用以下查詢:

SELECT * FROM Person WHERE name IN ('Betty', 'Charlie')

如要只傳回每個 Personname 值,請使用以下查詢:

SELECT name FROM Person

如要只傳回每個 Personname 值,並按照 age 排序,請使用以下查詢:

SELECT name FROM Person ORDER BY age

如要尋找 Person 類型實體的索引鍵,且該實體的年齡為 None (即 KEY('Person', 'georgemichael')),請使用以下查詢:

SELECT __key__ FROM Person WHERE age = NULL

如要尋找 Amy 的實體群組中 (亦即 Amy 和 Fred) 的所有實體,不限種類,請使用這個查詢:

SELECT * WHERE __key__ HAS ANCESTOR KEY(Person, 'Amy')

如要依 Key 比對,我們可以在限制條件左側使用 __key__。舉例來說,我們可以使用這個查詢取得使用者名稱以「a」開頭的所有 Person 實體。

SELECT * FROM Person WHERE __key__ >= KEY('Person', 'a') AND __key__ < KEY('Person', 'b')

注意:如果您使用等式建立查詢的 __key__,請考慮改用 get() 直接擷取實體。