Esecuzione di query su campi nidificati e ripetuti nell'SQL precedente

Questo documento descrive come eseguire query su dati nidificati e ripetuti nella sintassi delle query SQL precedente. La sintassi delle query preferita per BigQuery è GoogleSQL. Per informazioni sulla gestione dei dati nidificati e ripetuti in GoogleSQL, consulta la guida alla migrazione per GoogleSQL.

BigQuery supporta il caricamento e l'exporting di dati nidificati e ripetuti sotto forma di file JSON e Avro. Per molte query SQL precedente, BigQuery è in grado di suddividere automaticamente i dati. Ad esempio, molte istruzioni SELECT possono recuperare campi nidificati o ripetuti mantenendo la struttura dei dati e le clausole WHERE possono filtrare i dati mantenendone la struttura. Al contrario, le clausole ORDER BY e GROUP BY separano implicitamente i dati sottoposti a query. Nei casi in cui i dati non siano implicitamente suddivisi, ad esempio l'esecuzione di query su più campi ripetuti nell'SQL precedente, puoi eseguire query sui dati utilizzando le funzioni SQL FLATTEN e WITHIN.

FLATTEN

Quando esegui query su dati nidificati, BigQuery appiattisce automaticamente i dati della tabella. Diamo un'occhiata a uno schema di esempio per i dati delle persone:

   Last modified                 Schema                 Total Rows   Total Bytes   Expiration
 ----------------- ----------------------------------- ------------ ------------- ------------
  27 Sep 10:01:06   |- kind: string                     4            794
                    |- fullName: string (required)
                    |- age: integer
                    |- gender: string
                    +- phoneNumber: record
                    |  |- areaCode: integer
                    |  |- number: integer
                    +- children: record (repeated)
                    |  |- name: string
                    |  |- gender: string
                    |  |- age: integer
                    +- citiesLived: record (repeated)
                    |  |- place: string
                    |  +- yearsLived: integer (repeated)

Nota che ci sono diversi campi ripetuti e nidificati. Se esegui una query SQL precedente come la seguente sulla tabella delle persone :

SELECT
  fullName AS name,
  age,
  gender,
  citiesLived.place,
  citiesLived.yearsLived
FROM [dataset.tableId]

BigQuery restituisce i dati con un output suddiviso:

+---------------+-----+--------+-------------------+------------------------+
|     name      | age | gender | citiesLived_place | citiesLived_yearsLived |
+---------------+-----+--------+-------------------+------------------------+
| John Doe      |  22 | Male   | Seattle           |                   1995 |
| John Doe      |  22 | Male   | Stockholm         |                   2005 |
| Mike Jones    |  35 | Male   | Los Angeles       |                   1989 |
| Mike Jones    |  35 | Male   | Los Angeles       |                   1993 |
| Mike Jones    |  35 | Male   | Los Angeles       |                   1998 |
| Mike Jones    |  35 | Male   | Los Angeles       |                   2002 |
| Mike Jones    |  35 | Male   | Washington DC     |                   1990 |
| Mike Jones    |  35 | Male   | Washington DC     |                   1993 |
| Mike Jones    |  35 | Male   | Washington DC     |                   1998 |
| Mike Jones    |  35 | Male   | Washington DC     |                   2008 |
| Mike Jones    |  35 | Male   | Portland          |                   1993 |
| Mike Jones    |  35 | Male   | Portland          |                   1998 |
| Mike Jones    |  35 | Male   | Portland          |                   2003 |
| Mike Jones    |  35 | Male   | Portland          |                   2005 |
| Mike Jones    |  35 | Male   | Austin            |                   1973 |
| Mike Jones    |  35 | Male   | Austin            |                   1998 |
| Mike Jones    |  35 | Male   | Austin            |                   2001 |
| Mike Jones    |  35 | Male   | Austin            |                   2005 |
| Anna Karenina |  45 | Female | Stockholm         |                   1992 |
| Anna Karenina |  45 | Female | Stockholm         |                   1998 |
| Anna Karenina |  45 | Female | Stockholm         |                   2000 |
| Anna Karenina |  45 | Female | Stockholm         |                   2010 |
| Anna Karenina |  45 | Female | Moscow            |                   1998 |
| Anna Karenina |  45 | Female | Moscow            |                   2001 |
| Anna Karenina |  45 | Female | Moscow            |                   2005 |
| Anna Karenina |  45 | Female | Austin            |                   1995 |
| Anna Karenina |  45 | Female | Austin            |                   1999 |
+---------------+-----+--------+-------------------+------------------------+

In questo esempio, citiesLived.place ora è citiesLived_place e citiesLived.yearsLived è ora citiesLived_yearsLived.

Anche se BigQuery può suddividere automaticamente i campi nidificati, potrebbe essere necessario chiamare esplicitamente FLATTEN quando hai a che fare con più campi ripetuti. Ad esempio, se provi a eseguire una query SQL precedente come la seguente:

SELECT fullName, age
FROM [dataset.tableId]
WHERE
  (citiesLived.yearsLived > 1995 ) AND
  (children.age > 3)

BigQuery restituisce un errore simile al seguente:

Cannot query the cross product of repeated fields children.age and citiesLived.yearsLived

Per eseguire una query su più campi ripetuti, devi uniformare uno dei campi:

SELECT
  fullName,
  age,
  gender,
  citiesLived.place
FROM (FLATTEN([dataset.tableId], children))
WHERE
  (citiesLived.yearsLived > 1995) AND
  (children.age > 3)
GROUP BY fullName, age, gender, citiesLived.place

che restituisce:

+------------+-----+--------+-------------------+
|  fullName  | age | gender | citiesLived_place |
+------------+-----+--------+-------------------+
| John Doe   |  22 | Male   | Stockholm         |
| Mike Jones |  35 | Male   | Los Angeles       |
| Mike Jones |  35 | Male   | Washington DC     |
| Mike Jones |  35 | Male   | Portland          |
| Mike Jones |  35 | Male   | Austin            |
+------------+-----+--------+-------------------+

Clausola WITHIN

La parola chiave WITHIN utilizza in particolare le funzioni di aggregazione per aggregare i dati nei campi secondari e ripetuti all'interno di record e campi nidificati. Quando specifichi la parola chiave WITHIN, devi specificare l'ambito in base al quale vuoi aggregare:

  • WITHIN RECORD: aggrega i dati nei valori ripetuti all'interno del record.
  • WITHIN node_name: aggrega i dati nei valori ripetuti all'interno del nodo specificato, dove un nodo è un nodo padre del campo nella funzione di aggregazione.

Supponi di voler trovare il numero di figli di ogni persona nell'esempio precedente. A tale scopo, puoi contare il numero di children.name che ogni record ha:

SELECT
  fullName,
  COUNT(children.name) WITHIN RECORD AS numberOfChildren
FROM [dataset.tableId];

Ottieni il seguente risultato:

+---------------+------------------+
|   fullName    | numberOfChildren |
+---------------+------------------+
| John Doe      |                2 |
| Jane Austen   |                2 |
| Mike Jones    |                3 |
| Anna Karenina |                0 |
+---------------+------------------+

Per fare un confronto, prova a elencare tutti i nomi dei bambini:

SELECT fullName, children.name
FROM [dataset.tableId]
+---------------+---------------+
|   fullName    | children_name |
+---------------+---------------+
| John Doe      | Jane          |
| John Doe      | John          |
| Jane Austen   | Josh          |
| Jane Austen   | Jim           |
| Mike Jones    | Earl          |
| Mike Jones    | Sam           |
| Mike Jones    | Kit           |
| Anna Karenina | None          |
+---------------+---------------+

Questo corrisponde ai nostri risultati della query WITHIN RECORD. John Doe ha due figli che si chiamano Jane e John, Jane Austen ha due figli che si chiamano Josh e Jim, Mike Jones ha tre figli che si chiamano Conte, Sam e Kit e Anna Karenina non ha figli.

Ora, supponi di voler conoscere il numero di volte in cui una persona ha vissuto in luoghi diversi. Puoi utilizzare la clausola WITHIN per aggregare i dati in un determinato nodo:

SELECT
  fullName,
  COUNT(citiesLived.place) WITHIN RECORD AS numberOfPlacesLived,
  citiesLived.place,
  COUNT(citiesLived.yearsLived) WITHIN citiesLived AS numberOfTimesInEachCity,
FROM [dataset.tableId];
+---------------+---------------------+-------------------+-------------------------+
|   fullName    | numberOfPlacesLived | citiesLived_place | numberOfTimesInEachCity |
+---------------+---------------------+-------------------+-------------------------+
| John Doe      |                   2 | Seattle           |                       1 |
| John Doe      |                   2 | Stockholm         |                       1 |
| Mike Jones    |                   4 | Los Angeles       |                       4 |
| Mike Jones    |                   4 | Washington DC     |                       4 |
| Mike Jones    |                   4 | Portland          |                       4 |
| Mike Jones    |                   4 | Austin            |                       4 |
| Anna Karenina |                   3 | Stockholm         |                       4 |
| Anna Karenina |                   3 | Moscow            |                       3 |
| Anna Karenina |                   3 | Austin            |                       2 |
+---------------+---------------------+-------------------+-------------------------+

Questa query svolge le seguenti operazioni:

  • Esegue una WITHIN RECORD su citiesLived.place e conta il numero di luoghi in cui ha vissuto ogni persona
  • Esegue WITHIN il giorno citiesLived.yearsLived e conteggia il numero di volte in cui ogni persona ha vissuto in ciascuna città (contando solo citiesLived).

L'utilizzo dell'aggregazione mirata su campi nidificati e ripetuti è una delle funzionalità più potenti di BigQuery, che spesso consente di eliminare costosi join nelle query.