Este artigo é o primeiro de uma série sobre os fundamentos das expressões de tabela em T-SQL. Vou me concentrar principalmente em quatro tipos de expressões de tabela nomeada, que são conhecidas em T-SQL como tabelas derivadas, expressões de tabela comuns (CTEs), exibições e funções com valor de tabela inline (TVFs inline).
Fui inspirado a escrever esta série pelo meu bom amigo, Grant Fritchey, que conheço há muitos anos. Como Grant aponta repetidamente, muitos que usam expressões de tabela comuns em T-SQL pensam que o SQL Server mantém o conjunto de resultados de consulta interna e que o motivo dessa crença é o uso do termo tabela no nome da construção. Quando esse tópico surge nas discussões da comunidade, muitas vezes as pessoas argumentam que o uso do termo tabela no nome do construto é inadequado, pois não é realmente uma tabela. Existem até sugestões para iniciar uma campanha de nomenclatura na esperança de ver uma futura mudança de nome para essa construção, pelo menos em T-SQL. Algumas das sugestões incluem expressão de consulta , visualização em linha , visualização em nível de instrução , e outros.
Talvez isso seja uma surpresa para alguns, mas eu realmente acho o uso do termo tabela na expressão de tabela comum como muito apropriado. Na verdade, acho que o uso do termo expressão de tabela como apropriado. Para mim, a melhor maneira de descrever o que é um CTE em T-SQL, é uma expressão de tabela nomeada . O mesmo se aplica ao que o T-SQL chama de tabelas derivadas (a construção de linguagem específica em oposição à ideia geral), visualizações e TVFs inline. Todas são expressões de tabela nomeadas.
Se você puder ter um pouco de paciência comigo, fornecerei o raciocínio para minha visão das coisas neste artigo. Ocorreu-me que tanto a confusão de nomenclatura quanto a confusão sobre se há um aspecto de persistência nas expressões de tabela podem ser esclarecidas com uma melhor compreensão dos fundamentos do nosso campo de sistemas de gerenciamento de banco de dados relacional. Esses fundamentos são a teoria relacional, como o SQL (a linguagem padrão) se relaciona a ele e como o dialeto T-SQL usado nas implementações do SQL Server e do Banco de Dados SQL do Azure se relaciona com ambos.
Como ponto de partida, você deseja ser capaz de responder às seguintes perguntas:
- O que significa a independência de dados físicos princípio no modelo relacional significa?
- O que é uma tabela em SQL e qual é a contrapartida no modelo relacional?
- Qual é a propriedade de fechamento da álgebra relacional?
- O que é uma expressão de tabela e qual é a contrapartida no modelo relacional?
Depois de responder corretamente às perguntas acima, você provavelmente encontrará o uso do termo expressão de tabela nomeada conforme apropriado para as construções acima mencionadas (o que o T-SQL chama de tabelas derivadas, CTEs, exibições e TVFs inline).
Não quero parecer que tenho uma compreensão muito profunda da teoria relacional. Minha especialidade é T-SQL. Reconheço que há muito mais que não sei sobre teoria relacional do que sei, e que algumas coisas que acho que sei simplesmente não são. Quando leio os escritos de C. J. Dates sobre o assunto, sinto que mal estou arranhando a superfície do que há para saber, e que poderia e deveria me esforçar para entendê-lo melhor. Eu reconheço e acredito firmemente que uma boa compreensão da teoria relacional se traduz diretamente em uma melhor compreensão do SQL e do T-SQL e na escrita de código T-SQL melhor, mais preciso e mais robusto. Para quem escolhe dados como carreira, recomendo a leitura de SQL and Relational Theory:How to Write Accurate SQL Code 3rd Edition de C. J. Date (O'Reilly 2015).
Na primeira parte desta série, quero estabelecer uma compreensão do meu uso dos termos expressão de tabela e expressão de tabela nomeada , que está de acordo com o uso deste termo por Date e, infelizmente, não está de acordo com o uso deste termo pelo SQL Standard. Para conseguir isso, fornecerei um pouco de conhecimento da teoria relacional e do padrão SQL. Mas, como eu disse, recomendo a leitura do livro de Date para uma cobertura verdadeiramente detalhada deste tópico.
Começarei explicando o que significa o princípio da independência física de dados. A seguir, explicarei o que é uma tabela no SQL e sua contraparte na teoria relacional. Em seguida, explicarei o que significa a propriedade de fechamento da álgebra relacional. Uma vez que você tenha uma ideia razoável do que é uma tabela e o que significa a propriedade closure, fica bem simples entender o que é uma expressão de tabela. Meu foco então se voltará para as especificidades do T-SQL. Tenho muito a dizer sobre os fundamentos das expressões de tabela em T-SQL — tanto em termos de tratamento conceitual quanto em termos de detalhes de implementação, incluindo representação física e considerações de ajuste de consulta.
Acho este tópico fascinante e muito prático quando você se aprofunda nos detalhes da implementação. Na verdade, tenho tanto a dizer sobre isso que não tenho certeza de quantas partes essa série eventualmente envolverá. O que posso dizer com um grande grau de confiança é que haverá várias partes. Provavelmente mais de um e menos de 100. Em partes futuras, aprofundarei os tipos individuais de expressões de tabela nomeada, considerações de modificação, aspectos de inline, aspectos de ordenação, correlações e muito mais.
Em meus exemplos, usarei um banco de dados de exemplo chamado TSQLV5. Você pode encontrar o script que cria e preenche esse banco de dados aqui e seu diagrama ER aqui.
Independência de dados físicos
A independência de dados físicos é um princípio na teoria relacional que diz que os detalhes da implementação física devem ser ocultados ou transparentes para o usuário que envia as consultas no sistema de gerenciamento de banco de dados relacional. Nas consultas, os usuários devem se concentrar em o que eles precisam usar operações lógicas baseadas em álgebra relacional, em oposição a como para obter os dados. Eles não devem se preocupar com a forma como os dados são estruturados, acessados e processados. Tais detalhes de implementação física tendem a diferir substancialmente entre diferentes implementações (produtos RDBMS). Mesmo com o mesmo RDBMS, os detalhes da implementação física às vezes mudam entre diferentes versões e compilações. A ideia por trás do princípio de independência física de dados em teoria é proteger o investimento do usuário, eliminando a necessidade de revisar suas soluções quando você atualiza seu RDBMS para uma nova versão, ou mesmo quando você migra de um RDBMS para outro. Como você provavelmente sabe bem, na prática as coisas não são tão simples, mas isso é um tópico para uma discussão diferente.
O que é uma tabela?
Se você trabalha com T-SQL ou qualquer outro dialeto do SQL há algum tempo, você desenvolve uma compreensão intuitiva do que é uma tabela. O problema é que, sem alguma base de teoria relacional, muitas vezes a compreensão intuitiva não é muito precisa. Um erro típico é que intuitivamente tendemos a nos concentrar nos detalhes da implementação física. Por exemplo, quando você está pensando sobre o que é uma tabela, você está pensando em uma tabela como uma estrutura lógica (um conjunto de linhas) ou está pensando em detalhes de implementação física na plataforma que está usando (no SQL Server , páginas, extensões, heap versus índice clusterizado, índices não clusterizados e assim por diante)? Como um usuário escrevendo código SQL para consultar uma tabela, seguindo o princípio de independência física de dados, você deve pensar na tabela como uma estrutura lógica e deixar o RDBMS se preocupar com os detalhes da implementação física. Então, vamos dar um passo para trás e tentar descobrir o que é uma mesa.
Uma tabela é a contrapartida do SQL para a estrutura principal na teoria relacional — uma relação. Para manter as coisas simples e limitar o escopo da minha cobertura, não vou entrar na distinção entre uma variável de relação e um valor de relação. Se você seguir minha recomendação e ler o livro de Date, rapidamente terá uma visão clara de tais sutilezas.
Uma relação tem um título e um corpo.
O cabeçalho da relação é um conjunto de atributos . Na teoria matemática dos conjuntos, um conjunto não tem ordem nem duplicatas. Você deve identificar um atributo pelo nome e não por alguma posição. Consequentemente, os nomes dos atributos devem ser exclusivos.
Você consegue identificar qual é a contrapartida de um atributo no SQL? Você provavelmente adivinhou que é uma coluna . No entanto, o SQL realmente tem uma noção de ordem para suas colunas com base em sua ordem de aparecimento na instrução CREATE TABLE. Por exemplo, aqui está a instrução CREATE TABLE para a tabela Sales.Shippers no banco de dados TSQLV5:
CREATE TABLE Sales.Shippers ( shipperid INT NOT NULL IDENTITY, companyname NVARCHAR(40) NOT NULL, phone NVARCHAR(24) NOT NULL, CONSTRAINT PK_Shippers PRIMARY KEY(shipperid) );
Consulte a tabela usando o notório
SELECT *
, igual a:SELECT * FROM Sales.Shippers;
Quando executei esta consulta no meu sistema, obtive a seguinte saída:
shipperid companyname phone ---------- -------------- --------------- 1 Shipper GVSUA (503) 555-0137 2 Shipper ETYNR (425) 555-0136 3 Shipper ZHISN (415) 555-0138
O SQL garante que as colunas serão retornadas da esquerda para a direita com base na ordem de definição. Vou explicar o que acontece com as linhas em breve. O SQL ainda permite que você faça referência à posição ordinal da coluna da lista SELECT na cláusula ORDER BY, assim (não que eu recomende essa prática, nem Aaron Bertrand):
SELECT shipperid, companyname, phone FROM Sales.Shippers ORDER BY 2;
Essa consulta gera a seguinte saída:
shipperid companyname phone ---------- -------------- --------------- 2 Shipper ETYNR (425) 555-0136 1 Shipper GVSUA (503) 555-0137 3 Shipper ZHISN (415) 555-0138
O corpo de uma relação é um conjunto de tuplas . Novamente, lembre-se de que um conjunto não tem ordem nem duplicatas. Portanto, uma relação deve ter pelo menos uma chave candidata que permita identificar exclusivamente uma tupla. A contrapartida do SQL para uma tupla é uma linha . No entanto, no SQL você não é forçado a definir uma chave em uma tabela e, se não o fizer, pode acabar com linhas duplicadas. Mesmo se você tiver uma chave definida em sua tabela, poderá obter linhas duplicadas retornadas de uma consulta na tabela. Aqui está um exemplo:
SELECT country FROM HR.Employees;
Essa consulta gera a seguinte saída:
country -------- USA USA USA USA UK UK UK USA UK
Esta consulta não produz um resultado relacional devido à possibilidade de linhas duplicadas. Enquanto a teoria relacional é baseada na teoria dos conjuntos, a SQL é baseada na teoria dos multiconjuntos. Um multiconjunto (também conhecido como superconjunto ou bolsa) pode ter duplicatas. O SQL fornece uma ferramenta para eliminar duplicatas com uma cláusula DISTINCT, assim:
SELECT DISTINCT country FROM HR.Employees;
Essa consulta gera a seguinte saída:
country -------- UK USA
O que o SQL mantém da teoria relacional em termos do corpo da tabela é a propriedade sem ordem. A menos que você adicione uma cláusula ORDER BY na consulta, você não tem nenhuma garantia de que o resultado terá uma ordem específica entre as linhas. Portanto, o corpo do resultado da consulta acima é relacional, pelo menos no sentido de que não possui duplicatas e não possui ordem garantida.
Suponha que você consulte uma tabela no SQL Server e não inclua uma cláusula ORDER BY na consulta. Você espera que o SQL Server sempre retorne as linhas em alguma ordem específica como um comportamento garantido? Muitas pessoas fazem. Muitos pensam que você sempre obterá as linhas de volta com base na ordem do índice clusterizado. Esse é um bom exemplo de ignorar o princípio de independência de dados físicos e fazer suposições com base na intuição e talvez com base no comportamento observado no passado. A Microsoft sabe que uma consulta SQL sem uma cláusula ORDER BY não garante nenhuma ordem entre as linhas de resultado e, portanto, mesmo que no nível físico os dados residam em uma estrutura de índice, o SQL Server não precisa processar os dados no índice pedido. Ele pode optar, sob certas condições físicas, por fazê-lo, mas pode optar por não fazê-lo sob outras condições físicas. Lembre-se também de que os detalhes da implementação física podem mudar entre diferentes versões e compilações do produto. Se você quiser garantir que a consulta retornará as linhas de resultado em alguma ordem específica, sua única maneira de garantir isso é introduzir uma cláusula ORDER BY na consulta mais externa.
Como você provavelmente já percebeu, os designers do SQL realmente não viam como uma prioridade seguir a teoria relacional. E o que descrevi aqui são apenas alguns exemplos. Há muitos mais. Como mencionado anteriormente, meu objetivo neste artigo é apenas fornecer a base teórica crítica suficiente para esclarecer a confusão em torno das expressões de tabela, antes de começar a aprofundar os detalhes do T-SQL em artigos futuros.
O que é uma expressão de tabela?
Álgebra relacional (a álgebra que define operações sobre relações na teoria relacional) tem um fechamento propriedade. O que isso significa é que uma operação sobre relações produz uma relação. Um operador relacional opera em uma ou mais relações como entrada e produz uma única relação como saída. A propriedade closure permite aninhar operações. Uma expressão relacional é uma expressão que opera em relações e retorna uma relação. Uma expressão relacional, portanto, pode ser usada onde a álgebra relacional espera uma relação.
Se você pensar sobre isso, não é diferente das operações em números inteiros que produzem um resultado inteiro. Suponha que a variável @i seja uma variável inteira. A expressão @i + 42 produz um inteiro e, portanto, pode ser usada onde um inteiro é esperado, como em (@i + 42) * 2.
Dado que uma tabela em SQL é a contrapartida de uma relação na teoria relacional, embora não muito bem sucedida nisso, uma expressão de tabela em SQL é a contrapartida de uma expressão relacional. Como mencionado anteriormente, eu uso o termo expressão de tabela seguindo o uso desse termo por C. J. Dates. O padrão SQL tem uma série de termos confusos, alguns dos quais, temo, não são muito apropriados. Por exemplo, o SQL Standard usa o termo expressão de tabela para descrever especificamente uma expressão baseada nas cláusulas de consulta começando com uma cláusula FROM obrigatória e incluindo opcionalmente as cláusulas WHERE, GROUP BY, HAVING e WINDOW (a última não é suportada em T -SQL) e excluindo a cláusula SELECT. Aqui está a especificação do padrão:
7.4
Função
Especifique uma tabela ou uma tabela agrupada.
Formato
[
[
[
[
É verdade que o resultado do que o padrão chama de expressão de tabela é considerado uma tabela, mas você não pode usar essa expressão como uma consulta autônoma. A versão da data do termo expressão de tabela é, na verdade, mais próxima do que o padrão SQL chama de expressão de consulta . Aqui está a especificação do padrão para o que ele chama de expressão de consulta:
7.17
Função
Especifique uma tabela.
Formato
[
[
COM [ RECURSIVE ]
AS