Photo by National Cancer Institute on Unsplash
Linguagem de Manipulação de Dados no BigQuery: Como Realizar Consultas SQL Avançadas
O BigQuery é um serviço de armazenamento e análise de dados em nuvem, que suporta diversas linguagens de manipulação de dados (DML) para realizar consultas SQL avançadas. Com isso, é possível executar consultas complexas em grandes volumes de dados com rapidez e eficiência. Neste artigo, vamos discutir as principais linguagens de manipulação de dados suportadas pela ferramenta e como utilizá-las em suas consultas SQL.
Cláusula SELECT
Ele é usada para selecionar dados de uma tabela. É possível selecionar colunas específicas, filtrar dados com base em condições e aplicar funções de agregação a valores numéricos.
Exemplo de consulta SQL utilizando a cláusula SELECT
:
SELECT customer_id, SUM(price) as total_price
FROM orders
WHERE order_date >= '2022-01-01'
GROUP BY customer_id;
Nessa consulta, a cláusula SELECT seleciona o ID do cliente e o total de gastos em pedidos de cada cliente desde o início de 2022. A cláusula GROUP BY é usada para agrupar os dados por ID do cliente, permitindo calcular o total de gastos de cada cliente.
Cláusula INSERT
A cláusula INSERT é usada para inserir novas linhas em uma tabela. É possível inserir dados em uma única linha ou em várias linhas em uma única consulta.
Exemplo simples de uma consulta SQL utilizando a cláusula INSERT
:
INSERT INTO customers (id, name, email)
VALUES (123, 'João Silva', 'joao.silva@email.com');
Além disso, podemos utilizar o INSERT
com outras cláusulas.
Usando valores explícitos
INSERT dataset.Inventory (product, quantity)
VALUES ('top load washer', 10),
('front load washer', 20),
('dryer', 30),
('refrigerator', 10),
('microwave', 20),
('dishwasher', 30),
('oven', 5)
INSERT dataset.NewArrivals (product, quantity, warehouse)
VALUES ('top load washer', 100, 'warehouse #1'),
('dryer', 200, 'warehouse #2'),
('oven', 300, 'warehouse #3')
Utilizando instrução INSERT SELECT
INSERT dataset.Warehouse (warehouse, state)
SELECT *
FROM UNNEST([('warehouse #1', 'WA'),
('warehouse #2', 'CA'),
('warehouse #3', 'WA')])
Utilizando instrução WITH
como alternativa ao INSERT SELECT
INSERT dataset.Warehouse (warehouse, state)
WITH w AS (
SELECT ARRAY<STRUCT<warehouse string, state string>>
[('warehouse #1', 'WA'),
('warehouse #2', 'CA'),
('warehouse #3', 'WA')] col
)
SELECT warehouse, state FROM w, UNNEST(w.col)
Copiando conteúdo de uma tabela para outra
INSERT dataset.DetailedInventory (product, quantity, supply_constrained)
SELECT product, quantity, false
FROM dataset.Inventory
INSERT VALUES
utilizando uma subconsulta
INSERT dataset.DetailedInventory (product, quantity)
VALUES ('countertop microwave',
(SELECT quantity FROM dataset.DetailedInventory WHERE product = 'microwave'))
INSERT
sem utilizar os nomes das colunas
INSERT dataset.Warehouse VALUES('warehouse #4', 'WA'), ('warehouse #5', 'NY')
Utilização do INSERT
com tipos STRUCT
INSERT dataset.DetailedInventory
VALUES
('top load washer', 10, FALSE, [(CURRENT_DATE, "comment1")],("white","1 year",(30,40,28))),
('front load washer', 20, FALSE, [(CURRENT_DATE, "comment1")], ("beige","1 year",(35,45,30)))
Dado que a tabela tenha as colunas comments
e specifications
como um tipo STRUCT
, com os valores seguindo a ordem dos campos, ela será incluída. Veja uma saída de uma consulta de exemplo:
product | quantity | supply_constrained | comments | specifications | |
front load washer | 20 | false | [{"created":"2021-02-09","comment":"comment1"}] | {"color":"beige","warranty":"1 year","dimensions":{"depth":"35.0","height":"45.0","width":"30.0"}} | |
top load washer | 10 | false | [{"created":"2021-02-09","comment":"comment1"}] | {"color":"white","warranty":"1 year","dimensions":{"depth":"30.0","height":"40.0","width":"28.0"}} |
INSERT
com tipos ARRAY
CREATE TABLE IF NOT EXISTS dataset.table1 (names ARRAY<STRING>);
INSERT INTO dataset.table1 (names) VALUES (["name1","name2"])
Cláusula UPDATE
A cláusula UPDATE é usada para atualizar os valores existentes em uma ou mais colunas em uma tabela. Ao criar consultas com ele, pode vir com outras cláusulas:
WHERE
: as instruçõesUPDATE
precisam incluir a cláusulaWHERE
com uma condição pelo menos. Caso precise atualizar todas as linhas de uma tabela, useWHERE true
.FROM
: oUPDATE
pode utilizar opcionalmente a cláusulaFROM
, quando precisa especificar quais as linhas serão atualizadas na tabela de destino.
Sobre o FROM
, algumas advertências:
A cláusula
SET
ela pode referir a colunas de uma tabela de destino e colunas de qualquer itemFROM
. Se tiver conflitos de nomes, as referências não qualificadas são tratadas como ambíguas.Se a tabela de destino na cláusula
FROM
estiver presente, ela vai precisar ter um alias se quiser executar mesclagem automaticamenteSe uma linha de tabela estiver mesclada com zero linhas da cláusula
FROM
, ela não seria atualizadaSe uma linha de tabela estiver mesclada exatamente com uma linha da cláusula
FROM
, ela será atualizadaSe uma linha de tabela estiver mesclada com mais de uma linha da cláusula
FROM
, a consulta gerará o seguinte erro:UPDATE/MERGE must match at most one source row for each target row
.
Segue alguns exemplos de consultas SQL utilizando a cláusula UPDATE
:
UPDATE
com a cláusula WHERE
UPDATE dataset.Inventory SET quantity = quantity - 10 WHERE product like '%washer%'
UPDATE
usando mesclagens
UPDATE dataset.Inventory
SET quantity = quantity + (SELECT quantity FROM dataset.NewArrivals
WHERE Inventory.product = NewArrivals.product),
supply_constrained = false
WHERE product IN (SELECT product FROM dataset.NewArrivals)
Uma alternativa é associar as tabelas:
UPDATE dataset.Inventory i
SET quantity = i.quantity + n.quantity, supply_constrained = false
FROM dataset.NewArrivals n
WHERE i.product = n.product
UPDATE
de campos aninhados
UPDATE dataset.DetailedInventory
SET specifications.color = 'white',specifications.warranty = '1 year'
WHERE product like '%washer%'
Como alternativa, atualize todo o registro:
UPDATE dataset.DetailedInventory
SET specifications = STRUCT<color STRING, warranty STRING, dimensions STRUCT<depth FLOAT64, height FLOAT64, width FLOAT64>>('white', '1 year', NULL)
WHERE product like '%washer%'
UPDATE
de registros repetidos
UPDATE dataset.DetailedInventory
SET comments = ARRAY(
SELECT comment FROM UNNEST(comments) AS comment
UNION ALL
SELECT (CAST('2016-01-01' AS DATE), 'comment1')
)
WHERE product like '%washer%'
Dica
Se a coluna for do tipoSTRUCT
, ocolumn_name
pode referenciar um campo usando a notação de ponto, como por exemplo:struct1.field1
.
Cláusula DELETE
A cláusula DELETE é usada para remover linhas específicas de uma tabela. É importante explicar que a cláusula WHERE
é obrigatória para esse tipo de instrução. Caso precise excluir todas as linhas de uma tabela, defina o WHERE
como true
, como no exemplo abaixo:
DELETE FROM dataset.DetailedInventory WHERE true
Segue mais alguns exemplos:
DELETE
com cláusula WHERE
DELETE dataset.Inventory WHERE quantity = 0
DELETE
com uma subconsulta
DELETE dataset.Inventory i
WHERE i.product NOT IN (SELECT product from dataset.NewArrivals)
DELETE
com subconsulta, utilizando a cláusula EXISTS
DELETE dataset.Inventory
WHERE NOT EXISTS
(SELECT * from dataset.NewArrivals WHERE Inventory.product = NewArrivals.product)
Cláusula TRUNCATE TABLE
A cláusula TRUNCATE TABLE é uma operação que permite remover todos os dados de uma tabela de uma só vez. Ao contrário da cláusula DELETE
, que remove linhas específicas de uma tabela, a cláusula TRUNCATE TABLE remove todos os dados da tabela, sem levar em consideração nenhuma condição específica. Portanto, é importante ter cuidado ao utilizar essa cláusula para evitar a perda acidental de dados importantes.
A seguir, um exemplo de como usar a cláusula TRUNCATE TABLE no BigQuery:
TRUNCATE TABLE dataset.Inventory
Cláusula MERGE
A cláusula MERGE é uma operação suportada pelo BigQuery que combina as operações de INSERT, UPDATE e DELETE em uma única consulta SQL. Essa operação é usada para combinar dados de várias tabelas em uma única tabela, ou para atualizar ou inserir novas linhas em uma tabela existente com base em uma condição de correspondência.
Ela é útil quando se trabalha com grandes volumes de dados em diferentes fontes, pois permite combinar dados de forma mais eficiente e precisa. O BigQuery permite que você execute consultas MERGE usando instruções SQL padrão, o que torna a integração de dados mais fácil e eficiente.
Suponha que você tenha duas tabelas, "customers_old" e "customers_new", que contêm informações sobre clientes. A tabela "customers_old" contém informações desatualizadas, enquanto a tabela "customers_new" contém informações atualizadas. Você pode usar a cláusula MERGE
para combinar as duas tabelas e atualizar as informações desatualizadas na tabela "customers_old".
MERGE customers_old AS target
USING customers_new AS source
ON target.customer_id = source.customer_id
WHEN MATCHED THEN
UPDATE SET target.name = source.name, target.email = source.email
WHEN NOT MATCHED THEN
INSERT (customer_id, name, email)
VALUES (source.customer_id, source.name, source.email);
Nessa consulta, a cláusula MERGE combina as tabelas "customers_old" e "customers_new" com base no campo "customer_id". A cláusula WHEN MATCHED é usada para atualizar as informações desatualizadas na tabela "customers_old" com as informações atualizadas da tabela "customers_new". A cláusula WHEN NOT MATCHED é usada para inserir novas linhas na tabela "customers_old" com informações da tabela "customers_new" que não existiam anteriormente.
Vamos a um outro exemplo. Suponha que você tenha uma tabela chamada "orders", que contém informações sobre pedidos de clientes, incluindo o ID do cliente, a data do pedido e o valor total. Você pode usar a cláusula MERGE para inserir novos pedidos na tabela "orders" ou atualizar os valores dos pedidos existentes com base no ID do cliente e na data do pedido.
MERGE orders AS target
USING (
SELECT customer_id, order_date, SUM(price) as total_price
FROM new_orders
GROUP BY customer_id, order_date
) AS source
ON target.customer_id = source.customer_id AND target.order_date = source.order_date
WHEN MATCHED THEN
UPDATE SET target.total_price = source.total_price
WHEN NOT MATCHED THEN
INSERT (customer_id, order_date, total_price)
VALUES (source.customer_id, source.order_date, source.total_price);
Nessa consulta, a cláusula MERGE combina a tabela "orders" com uma subconsulta "new_orders", que contém informações sobre novos pedidos de clientes. A cláusula ON é usada para comparar o ID do cliente e a data do pedido em ambas as tabelas. A cláusula WHEN MATCHED é usada para atualizar os valores de pedidos existentes na tabela "orders" com os valores da subconsulta "new_orders". A cláusula WHEN NOT MATCHED é usada para inserir novos pedidos na tabela "orders" que não existiam anteriormente.
Para quem já tem familiaridade com bancos relacionais e SQL, vai se identificar com a maioria dos comandos aqui, e isso é bom, porque a curva de aprendizado é bem menor.