Utilizzare le query con più istruzioni

Questo documento descrive come utilizzare le query con più istruzioni in BigQuery, ad esempio come scrivere query con più istruzioni, utilizzare tabelle temporanee nelle query con più istruzioni, fare riferimento alle variabili nelle query con più istruzioni ed eseguire il debug delle query con più istruzioni.

Una query con più istruzioni è una raccolta di istruzioni SQL che puoi eseguire in un'unica richiesta. Con le query con più istruzioni, puoi eseguire più istruzioni in sequenza, con stato condiviso. Le query con più istruzioni possono avere effetti collaterali, ad esempio l'aggiunta o la modifica dei dati delle tabelle.

Le query con più istruzioni vengono spesso utilizzate nelle procedure archiviate e supportano le istruzioni nel linguaggio procedurale, che ti consentono di eseguire operazioni come definire le variabili e implementare il flusso di controllo.

Scrivere, eseguire e salvare query con più istruzioni

Una query con più istruzioni è composta da una o più istruzioni SQL separate da punti e virgola. Qualsiasi istruzione SQL valida può essere utilizzata in una query con più istruzioni. Le query con più istruzioni possono includere anche istruzioni di linguaggio procedurale, che ti consentono di utilizzare le variabili o implementare il flusso di controllo con le tue istruzioni SQL.

Scrivere una query con più istruzioni

Puoi scrivere una query con più istruzioni in BigQuery. La seguente query sull'istruzione con più query dichiara una variabile e la utilizza all'interno di un'istruzione IF:

DECLARE day INT64;
SET day = (SELECT EXTRACT(DAYOFWEEK from CURRENT_DATE));
if day = 1 or day = 7 THEN
  SELECT 'Weekend';
ELSE
  SELECT 'Weekday';
END IF

BigQuery interpreta qualsiasi richiesta con più istruzioni come una query con più istruzioni, a meno che le istruzioni non siano costituite interamente da istruzioni CREATE TEMP FUNCTION seguite da una singola istruzione SELECT. Ad esempio, la query seguente non è considerata una query con più istruzioni:

CREATE TEMP FUNCTION Add(x INT64, y INT64) AS (x + y);
SELECT Add(3, 4);

Eseguire una query con più istruzioni

Puoi eseguire una query con più istruzioni come qualsiasi altra query, ad esempio nella console Google Cloud o utilizzando lo strumento a riga di comando bq.

Esegui il test di una query con più istruzioni

Per stimare il numero di byte letti da una query con più istruzioni, puoi eseguire una prova. Un test di prova di una query con più istruzioni è il più preciso possibile per le query che contengono solo istruzioni SELECT.

Le esecuzioni di prova hanno una gestione speciale per i seguenti tipi di query e istruzioni:

  • Istruzioni CALL: la prova convalida l'esistenza della procedura chiamata e ha una firma corrispondente agli argomenti forniti. I contenuti della procedura chiamata e tutte le istruzioni successive all'istruzione CALL non vengono convalidate.
  • Istruzioni DDL: il test di prova convalida la prima istruzione DDL e poi si arresta. Tutte le istruzioni successive vengono ignorate.
  • Istruzioni DML: il test di prova convalida l'istruzione DML e poi continua a convalidare le istruzioni successive. In questo caso, le stime di byte si basano sulle dimensioni delle tabelle originali e non tengono conto del risultato dell'istruzione DML.
  • Istruzioni EXECUTE IMMEDIATE: la prova convalida l'espressione di query, ma non valuta la query dinamica stessa. Tutte le istruzioni che seguono l'istruzione EXECUTE IMMEDIATE vengono ignorate.
  • Query che utilizzano variabili in un filtro di partizionamento: la prova convalida la query iniziale e le istruzioni successive. Tuttavia, la prova non è in grado di calcolare il valore di runtime delle variabili in un filtro di partizionamento. Questo influisce sulla stima dei byte letti.
  • Query che utilizzano variabili nell'espressione timestamp di una clausola FOR SYSTEM TIME AS OF: la prova utilizza i contenuti attuali della tabella e ignora la clausola FOR SYSTEM TIME AS OF. Questo influisce sulla stima dei byte letti in caso di differenze di dimensioni tra la tabella attuale e l'iterazione precedente della tabella.
  • Istruzioni di controllo FOR, IF e WHILE: la prova si interrompe immediatamente. Le espressioni di condizione, i corpi dell'istruzione di controllo e tutte le istruzioni successive non vengono convalidate.

Le prove vengono eseguite secondo il criterio del "best effort" e il processo sottostante è soggetto a modifiche. Le prove sono soggette alle seguenti condizioni:

  • Una query che completa correttamente una prova potrebbe non essere eseguita correttamente. Ad esempio, le query potrebbero non riuscire in fase di runtime per motivi che non vengono rilevati dalle prove.
  • Una query eseguita correttamente potrebbe non completare una prova. Ad esempio, le query potrebbero non riuscire nelle prove a causa di motivi rilevati al momento dell'esecuzione.
  • Non è garantito che le prove eseguite correttamente oggi vengano eseguite sempre in futuro. Ad esempio, le modifiche all'implementazione di prova potrebbero rilevare errori in una query che in precedenza non erano stati rilevati.

Salvare una query con più istruzioni

Per salvare una query con più istruzioni, consulta Utilizzare le query salvate.

Utilizzare le variabili in una query con più istruzioni

Una query con più istruzioni può contenere variabili create dall'utente e variabili di sistema.

  • Puoi dichiarare le variabili create dall'utente, assegnare loro valori e farvi riferimento durante la query.

  • In una query puoi fare riferimento alle variabili di sistema e assegnare dei valori ad alcune di esse, ma a differenza delle variabili definite dall'utente, non devi dichiararle. Le variabili di sistema sono integrate in BigQuery.

Dichiarare una variabile creata dall'utente

Devi dichiarare le variabili create dall'utente all'inizio della query con più istruzioni o all'inizio di un blocco BEGIN. Le variabili dichiarate all'inizio della query con più istruzioni rientrano nell'ambito dell'intera query. Le variabili dichiarate all'interno di un blocco BEGIN hanno l'ambito del blocco. Non rientrano nell'ambito dell'istruzione END corrispondente. La dimensione massima di una variabile è 1 MB, mentre la dimensione massima di tutte le variabili utilizzate in una query con più istruzioni è 10 MB.

Puoi dichiarare una variabile con la dichiarazione procedurale DECLARE come questa:

DECLARE x INT64;

BEGIN
DECLARE y INT64;
-- Here you can reference x and y
END;

-- Here you can reference x, but not y

Imposta una variabile creata dall'utente

Dopo aver dichiarato una variabile creata dall'utente, puoi assegnarle un valore con l'istruzione SET procedurale come la seguente:

DECLARE x INT64 DEFAULT 0;
SET x = 10;

Imposta una variabile di sistema

Non puoi creare variabili di sistema, ma puoi sostituire il valore predefinito per alcune di esse, come indicato di seguito:

SET @@dataset_project_id = 'MyProject';

Puoi anche impostare e utilizzare implicitamente una variabile di sistema in una query con più istruzioni. Ad esempio, nella seguente query devi includere il progetto ogni volta che vuoi creare una nuova tabella:

BEGIN
  CREATE TABLE MyProject.MyDataset.MyTempTableA (id STRING);
  CREATE TABLE MyProject.MyDataset.MyTempTableB (id STRING);
END;

Se non vuoi aggiungere più volte il progetto ai percorsi delle tabelle, puoi assegnare l'ID progetto del set di dati MyProject alla variabile di sistema @@dataset_project_id nella query con più istruzioni. Questa assegnazione rende MyProject il progetto predefinito per il resto della query.

SET @@dataset_project_id = 'MyProject';

BEGIN
  CREATE TABLE MyDataset.MyTempTableA (id STRING);
  CREATE TABLE MyDataset.MyTempTableB (id STRING);
END;

Analogamente, puoi impostare la variabile di sistema @@dataset_id per assegnare un set di dati predefinito per la query. Ad esempio:

SET @@dataset_project_id = 'MyProject';
SET @@dataset_id = 'MyDataset';

BEGIN
  CREATE TABLE MyTempTableA (id STRING);
  CREATE TABLE MyTempTableB (id STRING);
END;

Puoi anche fare riferimento esplicito a variabili di sistema come @@dataset_id in molte parti di una query con più istruzioni. Per scoprire di più, consulta Fare riferimento a una variabile di sistema.

Riferimento a una variabile creata dall'utente

Dopo aver dichiarato e impostato una variabile creata dall'utente, puoi farvi riferimento in una query con più istruzioni. Se una variabile e una colonna hanno lo stesso nome, la colonna ha la precedenza.

Vengono restituiti column x + column x:

DECLARE x INT64 DEFAULT 0;
SET x = 10;

WITH Numbers AS (SELECT 50 AS x)
SELECT (x+x) AS result FROM Numbers;
+--------+
| result |
+--------+
| 100    |
+--------+

Questa operazione restituisce column y + variable x:

DECLARE x INT64 DEFAULT 0;
SET x = 10;

WITH Numbers AS (SELECT 50 AS y)
SELECT (y+x) AS result FROM Numbers;
+--------+
| result |
+--------+
| 60     |
+--------+

Fare riferimento a una variabile di sistema

Puoi fare riferimento a una variabile di sistema in una query con più istruzioni.

La seguente query restituisce il fuso orario predefinito:

BEGIN
  SELECT @@time_zone AS default_time_zone;
END;
+-------------------+
| default_time_zone |
+-------------------+
| UTC               |
+-------------------+

Puoi utilizzare le variabili di sistema con query DDL e DML. Ad esempio, ecco alcuni modi per utilizzare la variabile di sistema @@time_zone durante la creazione e l'aggiornamento di una tabella:

BEGIN
  CREATE TEMP TABLE MyTempTable
  AS SELECT @@time_zone AS default_time_zone;
END;
BEGIN
  CREATE OR REPLACE TABLE MyDataset.MyTable(default_time_zone STRING)
  OPTIONS (description = @@time_zone);
END;
BEGIN
  UPDATE MyDataset.MyTable
  SET default_time_zone = @@time_zone
  WHERE TRUE;
END;

In alcune posizioni le variabili di sistema non possono essere utilizzate nelle query DDL e DML. Ad esempio, non puoi utilizzare una variabile di sistema come nome di progetto, set di dati o nome di tabella. Questo genera un errore quando tenti di includere la variabile di sistema @@dataset_id in un percorso di tabella:

BEGIN
  CREATE TEMP TABLE @@dataset_id.MyTempTable (id STRING);
END;

Utilizzare le tabelle temporanee in una query con più istruzioni

Le tabelle temporanee consentono di salvare i risultati intermedi in una tabella. Le tabelle temporanee sono gestite da BigQuery, quindi non è necessario salvarle o gestirle in un set di dati. Ti viene addebitato il costo per l'archiviazione delle tabelle temporanee.

Puoi creare e fare riferimento a una tabella temporanea in una query con più istruzioni. Al termine dell'utilizzo della tabella temporanea, puoi eliminarla manualmente per ridurre al minimo i costi di archiviazione o attendere che BigQuery la elimini dopo 24 ore.

Crea una tabella temporanea

Puoi creare una tabella temporanea per una query con più istruzioni con l'istruzione CREATE TABLE. L'esempio seguente crea una tabella temporanea per archiviare i risultati di una query e utilizza la tabella temporanea in una sottoquery:

-- Find the top 100 names from the year 2017.
CREATE TEMP TABLE top_names(name STRING)
AS
 SELECT name
 FROM `bigquery-public-data`.usa_names.usa_1910_current
 WHERE year = 2017
 ORDER BY number DESC LIMIT 100
;
-- Which names appear as words in Shakespeare's plays?
SELECT
 name AS shakespeare_name
FROM top_names
WHERE name IN (
 SELECT word
 FROM `bigquery-public-data`.samples.shakespeare
);

Ad eccezione di TEMP o TEMPORARY, la sintassi è identica a CREATE TABLE.

Quando crei una tabella temporanea, non utilizzare un progetto o un qualificatore di set di dati nel nome della tabella. La tabella viene creata automaticamente in un set di dati speciale.

Riferimento a una tabella temporanea

Puoi fare riferimento a una tabella temporanea per nome per la durata della query con più istruzioni corrente. Sono incluse le tabelle temporanee create da una procedura all'interno della query con più istruzioni. Non puoi condividere le tabelle temporanee. Le tabelle temporanee risiedono in set di dati _script% nascosti con nomi generati in modo casuale. L'articolo Elenco dei set di dati descrive come elencare i set di dati nascosti.

Elimina tabelle temporanee

Puoi eliminare una tabella temporanea in modo esplicito prima del completamento della query con più istruzioni utilizzando l'istruzione DROP TABLE:

CREATE TEMP TABLE table1(x INT64);
SELECT * FROM table1;  -- Succeeds
DROP TABLE table1;
SELECT * FROM table1;  -- Results in an error

Al termine di una query con più istruzioni, la tabella temporanea esiste per un massimo di 24 ore.

Visualizza i dati della tabella temporanea

Dopo aver creato una tabella temporanea, puoi visualizzare la struttura della tabella e i dati al suo interno. Per visualizzare la struttura e i dati della tabella, segui questi passaggi:

  1. Nella console Google Cloud, vai alla pagina Explorer di BigQuery.

    Vai a Spazio di esplorazione

  2. Fai clic su Cronologia delle query.

  3. Scegli la query che ha creato la tabella temporanea.

  4. Nella riga Tabella di destinazione, fai clic su Tabella temporanea.

Qualifica le tabelle temporanee con _SESSION

Quando le tabelle temporanee vengono utilizzate insieme a un set di dati predefinito, i nomi delle tabelle non qualificati si riferiscono a una tabella temporanea, se esistente, o a una tabella nel set di dati predefinito. L'eccezione è per le istruzioni CREATE TABLE, dove la tabella di destinazione viene considerata una tabella temporanea solo se è presente la parola chiave TEMP o TEMPORARY.

Ad esempio, considera la seguente query con più istruzioni:

-- Create table t1 in the default dataset
CREATE TABLE t1 (x INT64);

-- Create temporary table t1.
CREATE TEMP TABLE t1 (x INT64);

-- This statement selects from the temporary table.
SELECT * FROM t1;

-- Drop the temporary table
DROP TABLE t1;

-- Now that the temporary table is dropped, this statement selects from the
-- table in the default dataset.
SELECT * FROM t1;

Puoi indicare esplicitamente che fai riferimento a una tabella temporanea qualificando il nome della tabella con _SESSION:

-- Create a temp table
CREATE TEMP TABLE t1 (x INT64);

-- Create a temp table using the `_SESSION` qualifier
CREATE TEMP TABLE _SESSION.t2 (x INT64);

-- Select from a temporary table using the `_SESSION` qualifier
SELECT * FROM _SESSION.t1;

Se utilizzi il qualificatore _SESSION per una query su una tabella temporanea che non esiste, la query con più istruzioni genera un errore che indica che la tabella non esiste. Ad esempio, se non esiste una tabella temporanea denominata t3, la query con più istruzioni genera un errore anche se esiste una tabella denominata t3 nel set di dati predefinito.

Non puoi utilizzare _SESSION per creare una tabella non temporanea:

CREATE TABLE _SESSION.t4 (x INT64);  -- Fails

Raccogli informazioni su un job di query con più istruzioni

Un job di query con più istruzioni contiene informazioni su una query con più istruzioni che è stata eseguita. Alcune attività comuni che puoi eseguire con i dati dei job includono la restituzione dell'ultima istruzione eseguita con la query con più istruzioni o la restituzione di tutte le istruzioni eseguite con la query con più istruzioni.

Restituisce l'ultima istruzione eseguita

Il metodo jobs.getQueryResults restituisce i risultati della query per l'ultima istruzione da eseguire nella query con più istruzioni. Se non è stata eseguita alcuna istruzione, non viene restituito alcun risultato.

Restituisce tutte le istruzioni eseguite

Per ottenere i risultati di tutte le istruzioni in una query con più istruzioni, enumera i job figlio e chiama jobs.getQueryResults su ciascuno di essi.

Enumera job figlio

Le query con più istruzioni vengono eseguite in BigQuery utilizzando jobs.insert, in modo simile a qualsiasi altra query, con query a più istruzioni specificate come testo della query. Quando viene eseguita una query con più istruzioni, vengono creati job aggiuntivi, detti job secondari, per ogni istruzione nella query con più istruzioni. Puoi enumerare i job figlio di una query con più istruzioni chiamando jobs.list, passando l'ID job di query a più istruzioni come parametro parentJobId.

Eseguire il debug di una query con più istruzioni

Ecco alcuni suggerimenti per il debug delle query con più istruzioni:

  • Utilizza l'istruzione ASSERT per dichiarare che una condizione booleana è vera.

  • Utilizza BEGIN...EXCEPTION...END per rilevare gli errori e visualizzare il messaggio di errore e l'analisi dello stack.

  • Utilizza SELECT FORMAT("....") per mostrare i risultati intermedi.

  • Quando esegui una query con più istruzioni nella console Google Cloud, puoi visualizzare l'output di ogni istruzione nella query con più istruzioni. Il comando "bq query" dello strumento a riga di comando bq mostra anche i risultati di ogni passaggio quando esegui una query con più istruzioni.

  • Nella console Google Cloud, puoi selezionare una singola istruzione all'interno dell'editor di query ed eseguirla.

Autorizzazioni

L'autorizzazione ad accedere a una tabella, un modello o un'altra risorsa viene verificata al momento dell'esecuzione. Se un'istruzione non viene eseguita o se non viene valutata un'espressione, BigQuery non controlla se l'utente che esegue la query con più istruzioni ha accesso a eventuali risorse a cui fa riferimento.

All'interno di una query con più istruzioni, le autorizzazioni per ogni espressione o istruzione vengono convalidate separatamente. Ad esempio:

SELECT * FROM dataset_with_access.table1;
SELECT * FROM dataset_without_access.table2;

Se l'utente che esegue la query ha accesso a table1 ma non a table2, la prima query ha esito positivo e la seconda non riesce. Anche il job di query con più istruzioni non riesce.

Vincoli di sicurezza

Nelle query con più istruzioni, puoi utilizzare l'SQL dinamico per creare istruzioni SQL in fase di runtime. Questa procedura è comoda, ma può offrire nuove opportunità di utilizzo improprio. Ad esempio, l'esecuzione della seguente query rappresenta una potenziale minaccia di sicurezza di iniezione SQL, poiché il parametro della tabella potrebbe essere filtrato in modo errato, consentire l'accesso ed essere eseguito in tabelle indesiderate.

-- Risky query vulnerable to SQL injection attack.
EXECUTE IMMEDIATE CONCAT('SELECT * FROM SensitiveTable WHERE id = ', @id);

Per evitare di esporre o di perdere dati sensibili in una tabella o di eseguire comandi come DROP TABLE per eliminare i dati in una tabella, le istruzioni procedurali dinamiche di BigQuery supportano diverse misure di sicurezza per ridurre l'esposizione agli attacchi di SQL injection, tra cui:

  • Un'istruzione EXECUTE IMMEDIATE non consente alla propria query, espansa con parametri e variabili di ricerca, di incorporare più istruzioni SQL.
  • L'esecuzione dinamica dei comandi seguenti è limitata: BEGIN/END, CALL, CASE, IF, LOOP, WHILE e EXECUTE IMMEDIATE.

Limitazioni del campo di configurazione

I seguenti campi delle query di configurazione del job non possono essere impostati per una query con più istruzioni:

  • clustering
  • create_disposition
  • destination_table
  • destination_encryption_configuration
  • range_partitioning
  • schema_update_options
  • time_partitioning
  • user_defined_function_resources
  • write_disposition

Prezzi

I prezzi per le query con più istruzioni includono gli addebiti per le query (quando si utilizza il modello di fatturazione on demand) e l'archiviazione per le tabelle temporanee. Quando usi le prenotazioni, l'utilizzo delle query è coperto dai costi della prenotazione.

Calcolo delle dimensioni delle query on demand

Se utilizzi la fatturazione on demand, BigQuery addebita i costi per le query con più istruzioni in base al numero di byte elaborati durante l'esecuzione delle query con più istruzioni.

Per ottenere una stima del numero di byte elaborati da una query con più istruzioni, puoi eseguire una prova.

Per queste query con più istruzioni si applicano i prezzi seguenti:

  • DECLARE: la somma dei byte analizzati per le tabelle cui viene fatto riferimento nell'espressione DEFAULT. Le istruzioni DECLARE senza riferimenti a tabelle non sono addebitate.

  • SET: la somma dei byte analizzati per le tabelle cui viene fatto riferimento nell'espressione. Le istruzioni SET senza riferimenti a tabelle non sono addebitate.

  • IF: la somma dei byte analizzati per le tabelle cui viene fatto riferimento nell'espressione della condizione. Le espressioni della condizione IF senza riferimenti a tabelle non sono addebitate. Eventuali istruzioni non eseguite all'interno del blocco IF non sono addebitate.

  • WHILE: la somma dei byte analizzati per le tabelle cui viene fatto riferimento nell'espressione della condizione. Le istruzioni WHILE senza riferimenti a tabelle nell'espressione della condizione non sono addebitate. Eventuali istruzioni non eseguite all'interno del blocco WHILE non sono addebitate.

  • CONTINUE o ITERATE: nessun costo associato.

  • BREAK o LEAVE: nessun costo associato.

  • BEGIN o END: nessun costo associato.

Se una query con più istruzioni ha esito negativo, il costo delle eventuali istruzioni fino all'errore continuerà a essere applicato. L'istruzione con esito negativo non sarà addebitata.

Ad esempio, il seguente codice campione contiene commenti che precedono ogni istruzione e spiegano gli eventuali costi applicati da ciascuna istruzione:

-- No cost, since no tables are referenced.
DECLARE x DATE DEFAULT CURRENT_DATE();
-- Incurs the cost of scanning string_col from dataset.table.
DECLARE y STRING DEFAULT (SELECT MAX(string_col) FROM dataset.table);
-- Incurs the cost of copying the data from dataset.big_table.  Once the
-- table is created, you are not charged for storage while the rest of the
-- multi-statement query runs.
CREATE TEMP TABLE t AS SELECT * FROM dataset.big_table;
-- Incurs the cost of scanning column1 from temporary table t.
SELECT column1 FROM t;
-- No cost, since y = 'foo' doesn't reference a table.
IF y = 'foo' THEN
  -- Incurs the cost of scanning all columns from dataset.other_table, if
  -- y was equal to 'foo', or otherwise no cost since it is not executed.
  SELECT * FROM dataset.other_table;
ELSE
  -- Incurs the cost of scanning all columns from dataset.different_table, if
  -- y was not equal to 'foo', or otherwise no cost since it is not executed.
  UPDATE dataset.different_table
  SET col = 10
  WHERE true;
END IF;
-- Incurs the cost of scanning date_col from dataset.table for each
-- iteration of the loop.
WHILE x < (SELECT MIN(date_col) FROM dataset.table) DO
  -- No cost, since the expression does not reference any tables.
  SET x = DATE_ADD(x, INTERVAL 1 DAY);
  -- No cost, since the expression does not reference any tables.
  IF true THEN
    -- LEAVE has no associated cost.
    LEAVE;
  END IF;
  -- Never executed, since the IF branch is always taken, so does not incur
  -- a cost.
  SELECT * FROM dataset.big_table;
END WHILE;

Per ulteriori informazioni, consulta Calcolo delle dimensioni delle query.

Prezzi di archiviazione

Ti vengono addebitati i costi per le tabelle temporanee create dalle query con più istruzioni. Puoi utilizzare le viste TABLE_STORAGE o TABLE_STORAGE_USAGE_TIMELINE per vedere lo spazio di archiviazione utilizzato da queste tabelle temporanee. Le tabelle temporanee risiedono in set di dati _script% nascosti con nomi generati in modo casuale.

Quote

Per informazioni sulle quote di query con più istruzioni, consulta Quote e limiti.

Visualizzare il numero di query con più istruzioni

Puoi visualizzare il numero di query a più istruzioni attive utilizzando la vista INFORMATION_SCHEMA.JOBS_BY_PROJECT. L'esempio seguente utilizza la vista INFORMATION_SCHEMA.JOBS_BY_PROJECT per mostrare il numero di query con più istruzioni dal giorno precedente:

SELECT
  COUNT(*)
FROM
  `region-us`.INFORMATION_SCHEMA.JOBS_BY_PROJECT
WHERE
  creation_time BETWEEN TIMESTAMP_SUB(CURRENT_TIMESTAMP(), INTERVAL 1 DAY) AND CURRENT_TIMESTAMP()
AND job_type = "QUERY"
AND state = 'RUNNING'
AND statement_type = 'SCRIPT'

Per saperne di più sull'esecuzione di query su INFORMATION_SCHEMA.JOBS per le query con più istruzioni, consulta Job di query con più istruzioni.