10th Jan 2024 10 minutos de leitura Você pode usar várias instruções WITH no SQL? Ignacio L. Bisso sql aprender sql WITH cte expressões comuns de tabela Índice É possível usar várias instruções WITH no SQL? A cláusula WITH no SQL Uso de várias instruções WITH no SQL Uso de declarações WITH múltiplas e aninhadas no SQL Uso da cláusula WITH para criar Consultas Recursivas Continue aprendendo sobre várias declarações WITH no SQL Um guia abrangente sobre várias instruções WITH em SQL, perfeito tanto para iniciantes quanto para especialistas. A cláusula SQL WITH permite que você defina uma CTE (expressão de tabela comum). Uma CTE é como uma tabela que é preenchida durante a execução da consulta. Você pode usar várias instruções WITH em uma consulta SQL para definir vários CTEs. Neste artigo, explicaremos como definir vários CTEs em uma única consulta. Também mostraremos como essa abordagem leva o poder expressivo de uma consulta SQL para o próximo nível. É possível usar várias instruções WITH no SQL? Sim! Abaixo está uma consulta simples que usa duas cláusulas WITH: WITH wine_exporting_country AS ( SELECT country FROM product WHERE product_name = ‘wine’ AND qty_exported > 0 ), car_exporting_country AS ( SELECT country FROM product WHERE product_name = ‘car’ AND qty_exported > 0 ) SELECT country FROM wine_exporting_country INTERSECT car_exporting_country Na consulta acima, há dois CTEs. O primeiro (em vermelho) é chamado wine_exporting_country e o segundo (em azul) é car_exporting_country. A consulta principal (em preto) faz referência às duas declarações WITH como tabelas regulares usando INTERSECT. A interseção das duas tabelas retornará somente os países presentes em ambos os resultados do CTE. Observe que você pode ver a palavra-chave WITH apenas uma vez. Após a cláusula WITH, você precisa colocar o nome do CTE, depois a palavra-chave AS e, finalmente, entre parênteses, a consulta SELECT para definir o CTE. Se quiser aprender a usar várias instruções WITH em uma consulta, recomendo nosso curso interativo Consultas Recursivas curso interativo. Ele ensina os detalhes da sintaxe da cláusula WITH em mais de 100 exercícios práticos. Ele aborda a sintaxe básica, várias instruções WITH e consultas recursivas - o uso mais complexo da sintaxe WITH. A cláusula WITH no SQL Vamos primeiro explicar como funciona a cláusula WITH. Ela cria uma espécie de tabela virtual (o CTE) em tempo real, que é criada e preenchida durante a execução de uma única instrução SQL; após a execução do SQL, a "tabela" do CTE é removida automaticamente. Para entender melhor a cláusula WITH, sugiro o artigo O que é um CTE? Neste artigo, usaremos uma tabela de banco de dados chamada product que rastreia os países e os produtos mais populares que eles produzem (por exemplo, azeite de oliva, vinho, carros). Ela registra a quantidade produzida, importada e exportada por cada país. A tabela também contém o preço do produto e a população do país. countryproduct familyproduct nameqty_ producedqty_ importedqty_ exportedunitsUnit pricecountry_ population Francefoodwine18000000013000150000000liter3067000000 Francevehiclecar300000650004000000unit1000067000000 Germanyvehiclecar400000350002000000unit1000083000000 Germanyfoodwine3000000800001450000liter3083000000 Germanyfoodbeer40000000035000200000000liter483000000 Spainfoodwine3000000100002000000liter4047000000 Spainfoodolive oil3000000090000028000000liter2047000000 Finlandtechnologysmartphone3000000500002500000dollar2005500000 Greecefoodolive oil1000000200000800000liter1810000000 Vejamos um exemplo simples de uma consulta que usa uma cláusula WITH para definir um CTE. Suponha que desejemos obter uma lista dos países que exportam mais azeite de oliva do que importam. Queremos que os resultados sejam ordenados pela quantidade produzida por cada país. Aqui está a consulta: WITH olive_oil_exporter AS ( SELECT country, qty_produced FROM product WHERE product_name = ‘olive oil’ AND qty_exported > qty_imported ) SELECT country FROM olive_oil_exporter ORDER BY qty_produced DESC; Nessa consulta, temos um CTE chamado olive_oil_exporter, que é como uma tabela com duas colunas: country e qty_produced. As linhas no CTE contêm apenas os países que exportam mais azeite de oliva do que importam. Depois disso, usamos um SELECT regular para consultar o CTE olive_oil_exporter para obter os nomes dos países, que ordenamos de forma decrescente pela quantidade de azeite de oliva produzida naquele país. Uso de várias instruções WITH no SQL Vamos supor que queremos categorizar os países em países produtores de alimentos e países produtores de tecnologia. Para ser um produtor de alimentos, um país deve exportar mais de 100 milhões de dólares em produtos alimentícios. Para ser um produtor de alta tecnologia, um país deve produzir mais de 1.000 dólares em produtos tecnológicos por habitante. Queremos um relatório com os nomes de todos os países e duas colunas chamadas is_a_food_producer e is_a_hightech_producer. A consulta SQL para esse relatório é: WITH food_producer AS ( SELECT country FROM products WHERE product_family = ‘food’ GROUP BY country HAVING SUM( qty_exported * unit_price) > 100000000 ) hightech_producer AS ( SELECT country FROM products WHERE product_family = ‘technology’ GROUP BY country HAVING SUM( qty_produced / country_population) > 1000 ) SELECT DISTINCT p.country, CASE WHEN fp.country IS NULL THEN ‘No’ ELSE ‘Yes’ END AS is_a_food_produced, CASE WHEN htp.country IS NULL THEN ‘No’ ELSE ‘Yes’ END AS is_a_hightech_produced, FROM products p LEFT JOIN food_producer fp ON fp.country = p.country LEFT JOIN hightech_producer htp ON htp.country = p.country Na consulta acima, podemos identificar claramente três consultas separadas. As duas primeiras consultas usam a cláusula WITH para definir duas tabelas CTE: food_producer e hightech_producer. A terceira consulta é a consulta principal, que consome as duas tabelas CTE criadas anteriormente. Após a cláusula WITH, você pode ver o nome da tabela CTE (food_producer), depois a subcláusula AS e, finalmente (entre parênteses), a consulta para esse CTE. Para o segundo CTE, a cláusula WITH não é necessária; basta colocar uma vírgula e, em seguida, repetir a mesma sintaxe começando com o nome do CTE. Ambos os CTEs food_producer e hightech_producer têm apenas uma coluna: country. A consulta principal obtém os nomes de todos os países da tabela producte, em seguida, é feita uma LEFT JOIN em cada um dos CTEs. Quando o LEFT JOIN não tem uma linha correspondente, significa que a resposta para esse país é "No"; quando há uma linha correspondente, o valor para esse país é "Yes". Antes de ir para a próxima seção, gostaria de sugerir o artigo Como Escrever Múltiplos CTEs em SQL. Nele, você pode encontrar muitos exemplos e explicações sobre CTEs. Uso de declarações WITH múltiplas e aninhadas no SQL Em alguns casos, precisamos de um segundo CTE que se baseia no primeiro CTE: um CTE aninhado. Em outras palavras, a consulta para definir o segundo CTE deve ter uma referência ao primeiro CTE. Vejamos um exemplo. Queremos obter o valor total em dólares exportado por países em produtos alimentícios. No mesmo relatório, queremos mostrar a porcentagem que esse valor representa no total de exportações do país para todos os tipos de produtos. A consulta é: WITH country_export_by_product AS ( SELECT country, product_family, SUM(qty_exported * unit_price) AS total_exports FROM product GROUP BY country, product_family ), country_export_total AS ( SELECT country, SUM(total_exports) AS total_exports_country FROM country_export_by_product GROUP BY country ) SELECT cp.country, product_family, cp.total_exports_food , ROUND((cp.total_exports_food / ct.total_exports_country) * 100, 2) AS percentage_of_total_exports FROM country_export_by_product cp JOIN country_export_total ct ON ct.country = cp.country ORDER BY country, product_family; Nessa consulta, criamos um CTE chamado country_export_by_product que tem as colunas country, product_family e total_exports (que representa o valor total desse produto exportado por esse país (em dólares)). Observe que a cláusula GROUP BY usa as colunas country e product_family. O próximo CTE chama-se country_export_total e é baseado no CTE anterior country_export_by_product. A ideia desse CTE é obter o valor total exportado por cada país com base no CTE anterior. Observe que no segundo CTE usamos uma cláusula GROUP BY country. A necessidade de níveis diferentes da cláusula GROUP BY é o motivo pelo qual temos dois CTEs. A consulta principal faz referência a ambos os CTEs, unindo-os pelo valor do país. Em seguida, a expressão TRUNC((cp.total_exports_food / ct.total_exports_country) * 100, 2) ... é usada para calcular a porcentagem que cada produto representa no total de exportações desse país. Em termos de sintaxe, você pode fazer com que um CTE faça referência a outro CTE na mesma consulta. Foi o que fizemos em nossa consulta: ao definir o CTE country_export_total, fizemos referência ao CTE country_export_by_product definido anteriormente. Observe que podemos nos referir à instrução WITH definida antes da instrução WITH atual, mas não às posteriores. Você pode fazer referência a cada instrução WITH várias vezes em outra instrução WITH ou em uma consulta principal. Em nosso exemplo, fizemos referência ao primeiro WITH definido (o country_export_by_product CTE) em dois lugares: No segundo WITH (o country_export_total CTE) e na consulta principal. Outras limitações relacionadas à sintaxe da cláusula WITH são: Você deve usar a palavra-chave WITH apenas uma vez, antes do primeiro CTE. Todos os CTEs são separados por vírgulas, mas não há vírgula antes da consulta principal. Isso segue o padrão de sintaxe: WITH cte_name1 AS (query1), cte_name2 AS (query2) main_query Sugiro o artigo CTEs SQL Explicados com Exemplos para obter vários outros exemplos de consultas WITH; eles demonstram como melhorar a organização e a legibilidade de suas consultas SQL usando CTEs. Uso da cláusula WITH para criar Consultas Recursivas Você usa a cláusula WITH no SQL para definir consultas recursivas. As consultas recursivas o ajudam a consultar estruturas hierárquicas (ou seja, organogramas, árvores ou gráficos). Você pode ler mais sobre a consulta de estruturas hierárquicas aqui. As consultas recursivas são baseadas na cláusula WITH. Para criar uma consulta recursiva, você só precisa de uma cláusula WITH, mas a consulta em WITH consiste em duas partes. As consultas recursivas são úteis quando as tabelas ou o modelo de dados do banco de dados têm um tipo de hierarquia implícita. Talvez a tabela de exemplo mais comum para explicar esse tópico seja a tabela típica employee com as colunas employee_id e manager_employee_id. Se quisermos que um relatório mostre todos os funcionários com os nomes de seus gerentes e o nível hierárquico do funcionário, podemos usar a seguinte consulta recursiva: WITH RECURSIVE company_hierarchy AS ( SELECT employee_id, firstname, lastname, manager_employee_id, 0 AS hierarchy_level FROM employees WHERE manager_employee_id IS NULL UNION ALL SELECT e.employee_id, e.firstname, e.lastname, e.manager_employee_id, hierarchy_level + 1 FROM employees e, company_hierarchy ch WHERE e.manager_employee_id = ch.employee_id ) SELECT ch.firstname AS employee_first_name, ch.lastname AS employee_last_name, e.firstname AS boss_first_name, e.lastname AS boss_last_name, hierarchy_level FROM company_hierarchy ch LEFT JOIN employees e ON ch.manager_employee_id = e.employee_id ORDER BY ch.hierarchy_level, ch.manager_employee_id; Nessa consulta, podemos ver a cláusula WITH RECURSIVE, que é usada para criar um CTE recursivo chamado company_hierarchy. O CTE terá todos os nomes dos funcionários com os nomes de seus gerentes. Observe que o CTE tem duas declarações SELECT conectadas por UNION ALL. A primeira SELECT é para obter o primeiro funcionário na consulta recursiva (CEO John Smith). O segundo SELECT do UNION é uma consulta que é executada várias vezes. Em cada execução, ela retorna o(s) funcionário(s) no próximo nível da hierarquia. Por exemplo, sua primeira execução retorna todos os funcionários que se reportam diretamente a John Smith. Finalmente, há uma terceira instrução SELECT; ela está fora do CTE. Ela seleciona os nomes dos funcionários, os nomes de seus chefes e o nível hierárquico. Os dados são extraídos do CTE e unidos à tabela employees. Usamos um LEFT JOIN porque queremos todos os dados do CTE (inclusive John Smith, que tem um valor NULL na coluna manager_id). Os resultados são mostrados em ordem crescente: primeiro pelo nível hierárquico, depois pelo employee_id do chefe. Abaixo está o resultado da consulta: employee_first_nameemployee_last_nameboss_first_nameboss_last_namehierarchy_level JohnSmithNULLNULL1 MaryDoeJohnSmith2 PeterGraueMaryDoe3 TomDorinMaryDoe4 Para saber mais sobre consultas recursivas, consulte o artigo O que é um CTE recursivo no SQL? Continue aprendendo sobre várias declarações WITH no SQL Neste artigo, abordamos o uso de várias instruções WITH em uma única consulta SQL. Também mencionamos como usar a cláusula WITH em consultas recursivas. Se você quiser continuar aprendendo sobre a cláusula WITH, recomendo nosso Consultas Recursivas curso, que oferece uma excelente oportunidade de praticar o tipo mais desafiador de consultas SQL. As várias instruções WITH são mais úteis quando você escreve relatórios SQL complexos. Se esse for o seu caso, também recomendo nossa Folha de consulta gratuita sobre SQL para análise de dados, que foi criada especificamente para ajudá-lo a escrever consultas complexas para análise de dados. Se quiser praticar SQL em um nível avançado, confira nossa trilha SQL Avançado Practice. Ela contém mais de 200 exercícios para ajudá-lo a praticar conceitos avançados de SQL. A cada dois meses, publicamos um novo curso de prática de SQL avançado em nossa trilha Monthly Trilha de Práticas em SQL. Você também pode obter todos esses cursos e outros em nosso plano Ilimitado Vitalício plano. O plano lhe dá acesso vitalício a todos os nossos cursos de SQL em vários níveis de proficiência e em quatro dialetos SQL. Inscreva-se hoje mesmo! Tags: sql aprender sql WITH cte expressões comuns de tabela