Создайте вложенное / повторяющееся поле, используя SQL в BigQuery, к которому можно обращаться с точечной нотацией (без UNNEST) - PullRequest
0 голосов
/ 03 октября 2019

Я пытаюсь построить структуру данных в BigQuery с использованием SQL, которая точно отражает структуру данных, которую я получаю при загрузке JSON. Это позволит мне запрашивать представление, используя SQL с точечной нотацией вместо необходимости UNNEST, что я понимаю, но многие из моих клиентов находят это крайне запутанным и не интуитивно понятным.

Если я создаю действительно простой фиктивный набор данных спару строк, а затем вложить, используя шаблон ARRAY_AGG (STRUCT ([список полей])):


    WITH
      flat_table AS (
      SELECT "BigQuery" AS name, 23 AS user_count, "Data Warehouse" AS data_thing, 5 AS ease_of_use, "Awesome" AS description UNION ALL
      SELECT "MySQL" AS name, 12 AS user_count, "Database" AS data_thing, 3 AS ease_of_use, "Solid" AS description
      )

    SELECT 
    name, user_count, 
    ARRAY_AGG(STRUCT(data_thing, ease_of_use, description)) AS attributes
    FROM flat_table 
    GROUP BY name, user_count

Затем сохранение и просмотр схемы показывает, что поле attributes имеет значение Type = RECORD и Mode = REPEATED,Имена полей схемы:


name                    
    user_count              
    attributes          
    attributes.data_thing   
    attributes.ease_of_use  
    attributes.description 

Если я посмотрю информацию COLUMN в запросе INFORMATION_SCHEMA.COLUMNS, то увижу, что поля attributes is_nullable = NO и data_type = ARRAY<STRUCT<data_thing STRING, ease_of_use INT64, description STRING>>

ЕслиЯ хочу запросить эту структуру, мне нужно использовать шаблон UNNEST, как показано ниже:


    SELECT
      name,
      user_count
    FROM
      nested_table,
      UNNEST(attributes)
    WHERE
      ease_of_use > 3

Однако, когда я загружаю следующее представление JSON тех же данных в BigQuery с автоматическим определением схемы:


    {"attributes":{"description":"Awesome","ease_of_use":5,"data_thing":"Data Warehouse"},"user_count":23,"name":"BigQuery"}
    {"attributes":{"description":"Solid","ease_of_use":3,"data_thing":"Database"},"user_count":12,"name":"MySQL"}

Схема выглядит почти идентичной после загрузки, за исключением того, что поле attributes равно Mode = NULLABLE (оно все еще Type = RECORD). INFORMATION_SCHEMA.COLUMNS показывает мне, что поле attributes теперь is_nullable = YES и data_type = STRUCT<data_thing STRING, ease_of_use INT64, description STRING>, то есть теперь может обнуляться, а не в массиве.

Однако самое интересное для меня - это то, что я могу теперь запрашиватьэта таблица использует точечную запись вместо шаблона UNNEST, поэтому приведенный выше запрос выглядит следующим образом:


    SELECT
      name,
      user_count
    FROM
      nested_table_json
    WHERE
      attributes.ease_of_use > 3

Что, возможно, легче читать даже в этом тривиальном случае. Однако, как только мы доберемся до более сложных структур данных с несколькими вложенными полями и многоуровневым вложением, шаблон UNNEST становится чрезвычайно трудным для написания, проверки качества и отладки. Шаблон точечной нотации выглядит гораздо более интуитивно понятным и масштабируемым.

Итак, мой вопрос: возможно ли построить структуру данных, эквивалентную загруженному JSON, путем написания запросов в SQL, что позволяет нам создавать запросы стандартного SQLиспользуя точечную запись и не требуя сложных шаблонов UNNEST?

1 Ответ

1 голос
/ 03 октября 2019

Если вы знаете, что ваш array_agg будет выдавать одну строку, вы можете отбросить запись ARRAY следующим образом:

SELECT 
    name, user_count, 
    ARRAY_AGG(STRUCT(data_thing, ease_of_use, description))[offset(0)] AS attributes

обратите внимание на использование OFFSET(0), таким образом, возвращаемый результат будет:

[
  {
    "name": "BigQuery",
    "user_count": "23",
    "attributes": {
      "data_thing": "Data Warehouse",
      "ease_of_use": "5",
      "description": "Awesome"
    }
  }
]

, который можно запросить с помощью точечной нотации.

Если вы хотите просто сгруппировать результат в STRUCT, вам не нужно array_agg.

WITH
      flat_table AS (
      SELECT "BigQuery" AS name, 23 AS user_count, struct("Data Warehouse" AS data_thing, 5 AS ease_of_use, "Awesome" AS description) as attributes UNION ALL
      SELECT "MySQL" AS name, 12 AS user_count, struct("Database" AS data_thing, 3 AS ease_of_use, "Solid" AS description)
      )

    SELECT 
    *
    FROM flat_table 
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...