Examinar a instrução SELECT

Concluído

Transact-SQL ou T-SQL é um dialeto da linguagem SQL padrão ANSI usada pelos produtos e serviços do Microsoft SQL. Ele é semelhante ao SQL padrão. A maior parte do nosso foco estará na instrução SELECT, que é de longe a que possui mais opções e variações dentre todas as instruções DML.

Vamos começar dando uma olhada em como uma instrução SELECT é processada. A ordem na qual uma instrução SELECT é escrita não é a ordem na qual ela é avaliada e processada pelo mecanismo SQL Server banco de dados.

Considere a consulta a seguir:

SELECT OrderDate, COUNT(OrderID) AS Orders
FROM Sales.SalesOrder
WHERE Status = 'Shipped'
GROUP BY OrderDate
HAVING COUNT(OrderID) > 1
ORDER BY OrderDate DESC;

A consulta consiste em uma instrução SELECT, que é composta por várias cláusulas, cada uma das quais define uma operação específica que deve ser aplicada aos dados que estão sendo recuperados. Antes de examinarmos a ordem de tempo de execução das operações, vamos examinar rapidamente o que essa consulta faz, embora os detalhes das várias cláusulas não sejam abordados neste módulo.

A cláusula SELECT retorna a coluna OrderDate e a contagem de valores OrderID, às quais é atribuído o nome (ou alias) Orders:

SELECT OrderDate, COUNT(OrderID) AS Orders

A cláusula FROM identifica que tabela é a origem das linhas da consulta; neste caso é a tabela Sales.SalesOrder:

FROM Sales.SalesOrder

A cláusula WHERE filtra linhas para fora dos resultados, mantendo apenas as linhas que atendem à condição especificada; nesse caso, os pedidos com status "enviado":

WHERE Status = 'Shipped'

A cláusula GROUP BY pega as linhas que atenderam à condição do filtro e as agrupa porOrderDate, de modo que todas as linhas com o mesmo OrderDate sejam consideradas como um único grupo, e uma linha será retornada para cada grupo:

GROUP BY OrderDate

Depois que os grupos são formados, a cláusula HAVING filtra os grupos com base em seu próprio predicado. Somente datas com mais de um pedido serão incluídas nos resultados:

HAVING COUNT(OrderID) > 1

Para fins de visualização dessa consulta, a cláusula final é ORDER BY, que classifica a saída em ordem decrescente de OrderDate:

ORDER BY OrderDate DESC;

Agora que você viu o que cada cláusula faz, vamos examinar a ordem na qual SQL Server realmente as avalia:

  1. A cláusula FROM é avaliada primeiro, para fornecer as linhas de origem para o restante da instrução. Uma tabela virtual é criada e passada para a próxima etapa.
  2. A cláusula WHERE é a próxima a ser avaliada, filtrando as linhas da tabela de origem que correspondem a um predicado. A tabela virtual filtrada é passada para a próxima etapa.
  3. GROUP BY é a seguinte, organizando as linhas na tabela virtual de acordo com os valores exclusivos encontrados na lista GROUP BY. Uma nova tabela virtual é criada, contendo a lista de grupos e é passada para a próxima etapa. A partir desse ponto no fluxo de operações, somente as colunas na lista GROUP BY ou funções de agregação podem ser referenciadas por outros elementos.
  4. A cláusula HAVING é avaliada em seguida, filtrando grupos inteiros com base em seu predicado. A tabela virtual criada na etapa 3 é filtrada e encaminhada para a próxima etapa.
  5. A cláusula SELECT finalmente é executada, determinando que colunas serão exibidas nos resultados da consulta. Como a cláusula SELECT é avaliada após as outras etapas, qualquer alias de coluna (em nosso exemplo, Orders) criado nela não pode ser usado na cláusula GROUP BY ou HAVING.
  6. A cláusula ORDER BY é a última a ser executada, classificando as linhas conforme determinado pela lista de colunas.

Para aplicar essa compreensão à nossa consulta de exemplo, aqui está a ordem lógica em tempo de execução da instrução SELECT acima:

FROM Sales.SalesOrder
WHERE Status = 'Shipped'
GROUP BY OrderDate 
HAVING COUNT(OrderID) > 1
SELECT OrderDate, COUNT(OrderID) AS Orders
ORDER BY OrderDate DESC;

Nem todas as possíveis cláusulas são necessárias em todas as instruções SELECT que você escreve. A única cláusula necessária é a cláusula SELECT, que pode ser usada sozinha em alguns casos. Normalmente, uma cláusula FROM também está incluída para identificar a tabela que está sendo consultada. Além disso, o Transact-SQL tem outras cláusulas que podem ser adicionadas.

Como você viu, as consultas T-SQL não são escritas na mesma ordem em que são avaliadas logicamente. A ordem de avaliação de tempo de execução determina os dados disponíveis para cada cláusula, uma vez que uma cláusula só tem acesso às informações já disponibilizadas a partir de uma cláusula já processada. Por esse motivo, é importante entender a verdadeira ordem de processamento lógico ao escrever consultas.

Selecionar todas as colunas

A cláusula SELECT geralmente é conhecida como a listaSELECT, porque lista os valores a serem retornados nos resultados da consulta.

A forma mais simples de usar uma cláusula SELECT é com o caractere asterisco (*) para retornar todas as colunas. Quando usado em consultas T-SQL, ele é chamado de estrela. Embora a opção SELECT* seja adequada para testes rápidos, evite usá-la no trabalho de produção, pelos seguintes motivos:

  • As alterações na tabela que adicionam ou reorganizam colunas serão refletidas nos resultados da consulta, o que pode resultar em uma saída inesperada para aplicativos ou relatórios que usam a consulta.
  • Retornar dados desnecessários poderá reduzir a velocidade das consultas e causar problemas de desempenho se a tabela de origem contiver um grande número de linhas.

O exemplo a seguir recupera todas as colunas da tabela (hipotética) Production.Product.

SELECT * FROM Production.Product;

O resultado dessa consulta é um conjunto de linhas que contém todas as colunas de todas as linhas da tabela, que pode ter esta aparência:

ProductID

Nome

ProductNum

Cor

StandardCost

ListPrice

Tamanho

Peso

ProductCatID

680

HL Road Frame - Black, 58

FR-R92B-58

Preto

1059.31

1431.5

58

1016.04

18

706

HL Road Frame - Red, 58

FR-R92R-58

Vermelho

1059.31

1431.5

58

1016.04

18

707

Sport-100 Helmet, Red

HL-U509-R

Vermelho

13.0863

34.99

35

708

Sport-100 Helmet, Black

HL-U509

Preto

13.0863

34.99

35

...

...

...

...

...

...

...

...

...

Escolhendo colunas específicas

Uma lista de colunas explícita permite que você tenha controle sobre exatamente quais colunas são retornadas e em que ordem. Cada coluna no resultado terá o nome da coluna como cabeçalho.

Por exemplo, considere a consulta a seguir, que usa novamente a tabela hipotética Production.Product.

SELECT ProductID, Name, ListPrice, StandardCost
‎FROM Production.Product;

Desta vez, os resultados incluem apenas as colunas especificadas:

ProductID

Nome

ListPrice

StandardCost

680

HL Road Frame - Black, 58

1431.5

1059.31

706

HL Road Frame - Red, 58

1431.5

1059.31

707

Sport-100 Helmet, Red

34.99

13.0863

708

Sport-100 Helmet, Black

34.99

13.0863

...

...

...

...

Selecionando expressões

Além de recuperar colunas armazenadas na tabela especificada, uma cláusula SELECT pode executar cálculos e manipulações que usam operadores para combinar colunas e valores ou várias colunas. O resultado do cálculo ou da manipulação deve ser um resultado escalar (de valor único) que será exibido no resultado como uma coluna separada.

Por exemplo, a consulta a seguir inclui duas expressões:

SELECT ProductID,
      Name + '(' + ProductNumber + ')',
  ListPrice - StandardCost
FROM Production.Product;

Os resultados dessa consulta podem ter a seguinte aparência:

ProductID

680

HL Road Frame - Black, 58(FR-R92B-58)

372.19

706

HL Road Frame - Red, 58(FR-R92R-58)

372.19

707

Sport-100 Helmet, Red(HL-U509-R)

21.9037

708

Sport-100 Helmet, Black(HL-U509)

21.9037

...

...

...

Há alguns elementos interessantes a serem observados sobre esses resultados:

  • As colunas retornadas pelas duas expressões não têm nenhum nome de coluna. Dependendo da ferramenta que você está usando para enviar sua consulta, um nome de coluna ausente pode ser indicado por um cabeçalho de coluna em branco, um indicador literal de "nenhum nome de coluna" ou um nome padrão como column1. Veremos como especificar um alias para o nome da coluna na consulta mais adiante nesta seção.
  • A primeira expressão usa o operador+ para concatenar valores de cadeia de caracteres (com base em caracteres), enquanto a segunda expressão usa o operador - para subtrair um valor numérico de outro. Quando usado com valores numéricos, o operador + realiza adição. Nesse caso, é claramente importante entender os tipos de dados das colunas que você inclui em expressões. Discutiremos os tipos de dados na próxima seção.

Especificando aliases de coluna

Você pode especificar um alias para cada coluna retornada pela consulta SELECT, como uma alternativa ao nome da coluna de origem ou para atribuir um nome à saída de uma expressão.

Por exemplo, aqui está a mesma consulta que antes, mas com aliases especificados para cada uma das colunas:

SELECT ProductID AS ID,
      Name + '(' + ProductNumber + ')' AS ProductName,
  ListPrice - StandardCost AS Markup
FROM Production.Product;

Os resultados dessa consulta incluem os nomes de coluna especificados:

ID

ProductName

Marcação

680

HL Road Frame - Black, 58(FR-R92B-58)

372.19

706

HL Road Frame - Red, 58(FR-R92R-58)

372.19

707

Sport-100 Helmet, Red(HL-U509-R)

21.9037

708

Sport-100 Helmet, Black(HL-U509)

21.9037

...

...

...

Observação

A palavra-chave AS é opcional ao especificar um alias, mas é uma boa prática incluí-lo para esclarecimento.

Formatar consultas

Você pode observar nos exemplos desta seção que você pode ser flexível sobre como formatar o código de consulta. Por exemplo, você pode escrever cada cláusula (ou a consulta inteira) em uma única linha ou quebrá-la em várias linhas. Na maioria dos sistemas de banco de dados, o código não diferencia maiúsculas de minúsculas, e alguns elementos da linguagem T-SQL são opcionais (incluindo a palavra-chave AS, conforme mencionado anteriormente e até mesmo o ponto e vírgula no final de uma instrução).

Considere as diretrizes a seguir para tornar seu código T-SQL facilmente acessível (e, portanto, mais fácil de entender e depurar!):

  • Use maiúsculas para palavras-chave T-SQL, como SELECT, FROM, AS e assim por diante. Escrever palavras-chave em maiúsculas é uma convenção comumente usada, que torna mais fácil localizar cada cláusula de uma instrução complexa.
  • Inicie uma nova linha para cada cláusula principal de uma instrução.
  • Se a lista SELECT contiver muitas colunas, expressões ou aliases, considere listar cada coluna em sua própria linha.
  • Recuar linhas contendo subcláusulas ou colunas para tornar claro qual código pertence a cada cláusula principal.