0% acharam este documento útil (0 voto)
69 visualizações156 páginas

Apostila - Módulo 0 - A Linguagem SQL

Apostila de TI sobre SQL e suas aplicações, bem introdutória mas interessante
Direitos autorais
© © All Rights Reserved
Levamos muito a sério os direitos de conteúdo. Se você suspeita que este conteúdo é seu, reivindique-o aqui.
Formatos disponíveis
Baixe no formato PDF, TXT ou leia on-line no Scribd
0% acharam este documento útil (0 voto)
69 visualizações156 páginas

Apostila - Módulo 0 - A Linguagem SQL

Apostila de TI sobre SQL e suas aplicações, bem introdutória mas interessante
Direitos autorais
© © All Rights Reserved
Levamos muito a sério os direitos de conteúdo. Se você suspeita que este conteúdo é seu, reivindique-o aqui.
Formatos disponíveis
Baixe no formato PDF, TXT ou leia on-line no Scribd
Você está na página 1/ 156

A Linguagem SQL

Prof. Gustavo Aguilar


2023
SUMÁRIO
Capítulo 1. Introdução à Linguagem SQL ............................................................. 5

1.1. Banco de dados relacional: uma breve revisão ...................................................... 5

1.2. História da linguagem SQL .......................................................................................... 15

1.3. Padronização da linguagem SQL, classes de instruções SQL e dialetos 21

1.4. Uma “Sopa de Letras”..................................................................................................... 25

Capítulo 2. Introdução ao SQL Server ................................................................. 30

2.1. Introdução ao SQL Server ............................................................................................ 30

2.2. Conceitos básicos do SQL Server ............................................................................. 31

2.3. Instalação do SQL Server ............................................................................................. 31

2.4. Introdução à T-SQL ......................................................................................................... 31

2.5. Instalação e overview das ferramentas Client ................................................... 37

2.6. Banco de dados de exemplo AdventureWorks ................................................... 38

Capítulo 3. Linguagem de Definição de Dados (DDL) ................................... 40

3.1. Criação de estruturas de dados ................................................................................. 42

3.2 Alteração de estruturas de dados.............................................................................. 44

3.3. Remoção de estruturas de dados ............................................................................. 46

Capítulo 4. Linguagem de Manipulação de Dados (DML)............................ 49

4.1. Selecionando dados ........................................................................................................ 49

4.2. Operadores aritméticos e de concatenação ........................................................ 53

4.3. Ordenando dados ............................................................................................................. 56

4.4. Filtrando dados.................................................................................................................. 59

4.5. Funções de caracteres, de data e hora................................................................... 64

4.6. Tipos de dados e conversões Explícitas x Implícitas ...................................... 76

Capítulo 5. Agrupamento de Dados e Funções de Agregação .................. 80

5.1. Funções de agregação ................................................................................................... 80

2
5.2. Agrupamentos de dados ............................................................................................... 84

Capítulo 6. Junção de Tabelas (JOIN) ................................................................. 91

6.1. Introdução à Junção de Tabelas............................................................................... 91

6.2. INNER JOIN, CROSS JOIN e OUTER JOIN ......................................................... 95

Capítulo 7. Subconsultas ........................................................................................ 104

7.1. Subconsulta escalar e multivalorada ....................................................................104

7.2. Subconsultas correlacionadas e com operadores de conjuntos..............110

Capítulo 8. Inserção, Atualização e Exclusão de Dados ........................... 120

8.1. Inserindo Dados .............................................................................................................120

8.2. Atualizando Dados .........................................................................................................123

8.3. Excluindo dados ..............................................................................................................125

Capítulo 9. Linguagem de Controle de Transação (TCL) .......................... 130

9.1. Conceitos Básicos de Transação .............................................................................130

9.2. Controle de Transações ............................................................................................... 132

Capítulo 10. Linguagem de Controle de Acesso a Dados (DCL) ............ 136

10.1. Segurança em Bancos de Dados ..........................................................................136

10.2. Concessão e revogação de privilégios ............................................................... 138

Capítulo 11. Programação com a Linguagem T-SQL.................................. 141

11.1. Visões (Views) e CTEs ................................................................................................ 141

11.2. Stored Procedures.......................................................................................................145

11.3. Functions ......................................................................................................................... 149

11.4. Triggers ............................................................................................................................ 150

11.5. Linked Server e Query Distribuída .......................................................................151

Referências ...................................................................................................................... 153

3
1
Capítulo 1. Introdução à Linguagem SQL
Quando falamos de Linguagem SQL (abreviatura para Structured
Query Language, traduzido para o português como Linguagem Estruturada
de Consulta), estamos intrinsicamente falando da Teoria de Banco de Dados
Relacional, mais especificamente de modelos de dados e bancos de dados
relacionais.

Desde o advento dos sistemas gerenciadores de bancos de dados


relacionais (SGBDR ou RDBMS, abreviatura para Relational Database
Management System), a linguagem SQL é, sem dúvida, a linguagem de
consulta e manipulação de dados mais utilizada em projetos de
desenvolvimento de sistemas e aplicações apoiadas em bancos de dados.
Conhecer não somente os comandos e opções existentes nessa linguagem,
mas saber o contexto em que ela está inserida e dominar a teoria relacional
a partir da qual ela foi concebida são aspectos fundamentais para o sucesso
de um projeto de banco de dados.

1.1. Banco de dados relacional: uma breve revisão


O Modelo de Dados Relacional foi criado por Edgar Frank Codd, em
junho de 1970, na publicação do seu artigo A Relational Model of Data for
Large Shared Data Banks. Nesse artigo, Codd propôs um modelo onde a
representação dos dados é independente de como eles são organizados e
armazenados internamente nos servidores.

O grande sucesso da proposta de


Codd está no fato dele ter se baseado na
álgebra relacional e teoria de conjuntos,
trazendo para a comunidade um conceito
simplificado e mais trivial para o
raciocínio lógico de desenvolvedores e

5
projetistas de bancos de dados: dados vistos como um conjunto de tabelas,
dispostos em linhas e colunas.

Com um determinado registro (dados inter-relacionados) sendo


visto como uma tupla (linha formada por uma lista ordenada de colunas), a
representação tabular trouxe grande facilidade para manipular e visualizar
dados, em detrimento dos modelos hierárquicos e de rede em voga na época,
contribuindo enormemente para o “boom” dos bancos de dados relacionais.

Figura 1 – Exemplo de Armazenamento Tabular.

COD_CLIENTE NOM_CLIENTE NUM_TEL_CLIENTE IND_SEXO_CLIENTE


1 JOÃO 33333333 M
2 MARIA 99999999 F
3 JOSÉ 88888888 M
4 TIAGO 66666666 M
5 PEDRO 44444444 M
6 MATEUS 11111111 M
7 ANA 77777777 F
8 TEREZA 55555555 F
9 CLLODDOVILL 90000000 D
Fonte: Gustavo Aguilar (2002).

Junto com a teoria da representação tabular dos dados, Codd


apresentou os conceitos e recursos a serem usados na modelagem
relacional, descritos a seguir:

 Tabela: objeto correspondente à entidade do modelo conceitual,


constituindo a estrutura onde os dados serão armazenados no
modelo físico do banco de dados.

 Domínio: natureza dos valores permitidos para um determinado


conjunto de dados. Exemplos:

CÓDIGO CLIENTE  NUMBER

NOME CLIENTE  STRING

DATA NASCIMENTO  DATE

6
 Coluna: correspondente ao conceito de atributo do modelo
conceitual, acrescido do domínio do dado que será armazenado na
coluna. Comumente chamado de campo.

 Chave Primária (“Primary Key” / “PK”): coluna (campo) ou conjunto


de colunas (chave primária composta), que identificam unicamente
a tupla (linha) em uma tabela. Exemplo: número do CPF.

 Chave Candidata: que não repetem valor em uma tabela e que são
candidatas à chave primária. Exemplos:

NÚMERO DO TÍTULO DO ELEITOR

NÚMERO DO RG

NÚMERO DO CPF

 Chave Estrangeira (“Foreign Key” / “FK”): é o elo de ligação entre


duas tabelas, se constituindo na(s) coluna(s) da chave primária da
tabela estrangeira, relacionada com a tabela em questão.

Figura 2 – Exemplo de Chave Estrangeira (FK).

Fonte: Gustavo Aguilar (2002).

 Relacionamento: aplica-se o mesmo princípio do modelo conceitual


para o mapeamento das relações entre as tabelas, sendo que alguns
relacionamentos podem gerar novas tabelas.

 Cardinalidade: no modelo lógico relacional, assume uma


importância ainda maior, pois além de representar a quantidade de
elementos de uma entidade A que podem ser associados a

7
elementos de uma entidade B e vice-versa, indicam também as
restrições de nulidade das chaves estrangeiras.

No modelo lógico, uma das notações mais usadas para a


cardinalidade de relacionamentos é a Information Engineering (IE),
mostrada a seguir.

Figura 3 – Notação IE.

Fonte: Gustavo Aguilar (2002).

Essa notação, no tocante à chave estrangeira, indica a nulidade


dessa coluna, ou seja, se ela sempre estará associada a um registro da outra
tabela ou se a chave estrangeira aceitará um valor nulo. Cardinalidades 0,1
e 0,N implicam em chaves estrangeiras que aceitam valores nulos, como
mostrado no exemplo abaixo:

Figura 4 – Exemplo de Relacionamento 0,1:0,N.


PRODUTO
COD_PRODUTO: Number NOT NULL TIPO_PRODUTO
NOM_PRODUTO: String NOT NULL
COD_TIPO_PRODUTO: Number NOT NULL
COD_TIPO_PRODUTO: Number NULL (FK)
DSC_TIPO_PRODUTO: String NULL
DSC_PRODUTO: String NULL
VLR_PRODUTO: Number NOT NULL

Fonte: Gustavo Aguilar (2002).

Já as cardinalidades 1:0,N e 1:0,1 garantem que as chaves


estrangeiras não aceitem nulo e estejam sempre associadas com um
registro da tabela estrangeira, como mostrado no exemplo a seguir.

Figura 5 – Exemplo de Relacionamento 1:0,N.


PRODUTO
COD_PRODUTO: Number NOT NULL TIPO_PRODUTO
NOM_PRODUTO: String NOT NULL
COD_TIPO_PRODUTO: Number NOT NULL
COD_TIPO_PRODUTO: Number NOT NULL (FK)
DSC_TIPO_PRODUTO: String NULL
DSC_PRODUTO: String NULL
VLR_PRODUTO: Number NOT NULL

Fonte: Gustavo Aguilar (2002).

8
 Restrições de integridade: regra que garante a consistência dos
dados em um relacionamento entre duas tabelas. São de três tipos:

– Cascade (C): ao deletar um registro, deleta o registro da


chave estrangeira também (deleção em cascata).

– Restricit (R): não deleta um registro que seja chave


estrangeira.

– Set Null (S): deleta registro e seta chave estrangeira para


nulo.

A representação da restrição de integridade é sempre feita no


sentido tabela com a chave primária  tabela com a chave estrangeira,
como mostrado nos exemplos abaixo.

Figura 6 – Exemplos Restrições de Integridade.

Fonte: Gustavo Aguilar (2002).

9
Para definir corretamente as restrições de integridade, pode-se usar
o algoritmo a seguir como regra geral:

Posso eliminar chave primária (registro pai)?

Se não puder  RESTRICT

Se puder:

Preciso manter os Filhos (registros na tabela da FK)?

Se precisar  SET NULL

Se não precisar  CASCADE

Exemplo de modelo físico de dados para o sistema de uma agência


de turismo, a ser implementado no SGBD Oracle:

Figura 7 – Exemplo de Modelo Físico de Dados para Oracle.


SERVICO
CLIENTE
COD_SERVICO: NUMBER(3)
COD_CLIENTE: NUMBER(5)
COD_FORNECEDOR: NUMBER(3) (FK)
NOM_CLIENTE: VARCHAR2(50)
COD_FORMA_PAGAMENTO: NUMBER(2) (FK)
DSC_ENDERECO_COBRANCA: VARCHAR2(100) FK_FORNEC_SERVICO_01
DSC_SERVICO: VARCHAR2(50)
NUM_TELEFONE: NUMBER(12)
VLR_SERVICO: NUMBER(10,2)

FK_SERVICO_ITSOLSER_01
FK_CLIENTE_SOLISERV_01
FORNECEDOR
COD_FORNECEDOR: NUMBER(3)
NOM_FORNECEDOR: VARCHAR2(50)
ITEM_SOLICITACAO_SERVICO DSC_ENDERECO: VARCHAR2(100)
COD_ITEM_SOLICITACAO: NUMBER(5) NUM_TELEFONE: NUMBER(12)
NUM_SOLICITACAO_SERVICO: NUMBER(5) (FK)
COD_SERVICO: NUMBER(3) (FK)
FK_FORMAPAG_SERVICO_01
QTD_SERVICO: NUMBER(2)
VLR_TOTAL_ITEM: NUMBER(10,2) FORMA_PAGAMENTO
COD_FORMA_PAGAMENTO: NUMBER(2)
DSC_FORMA_PAGAMENTO: VARCHAR2(20)
FK_SOLISERV_ITSOLSER_01

FK_FORMAPAG_SOLISERV_01
SOLICITACAO_SERVICO
NUM_SOLICITACAO_SERVICO: NUMBER(5)
COD_CLIENTE: NUMBER(5) (FK)
COD_ATENDENTE: NUMBER(3) (FK) ATENDENTE
DAT_SOLICITACAO: DATE FK_ATEND_SOLISERV_01 COD_ATENDENTE: NUMBER(3)
VLR_TOTAL_SOLICITACAO: NUMBER(10,2) NOM_ATENDENTE: VARCHAR2(50)
IND_UNIFICACAO_FORMA_PAGAMENTO: CHAR(1)
COD_FORMA_PAGAMENTO: NUMBER(2) (FK)

Fonte: Gustavo Aguilar (2002).

Além de todo esse trabalho espetacular de lançamento do modelo


relacional, no ano de 1981, Codd publicou um conjunto de 12 regras, as
famosas 12 Regras de Codd (disponível em:
https://computing.derby.ac.uk/c/codds-twelve-rules), com o propósito de
definir o que seria necessário para um sistema de gerenciamento de bancos
de dados ser considerado relacional. Codd publicou essas regras como parte

10
de uma empreitada pessoal, na tentativa de impedir que sua visão e seu
trabalho acerca de bancos de dados relacionais fossem deturpadas ou
diluídas, dados os constantes esforços de fornecedores de bancos de dados
em ajustar ou redesenvolver os produtos existentes na época (SGBDs
hierárquicos, de rede etc.) com um viés relacional.

Essas regras são numeradas de 1 à 12, mas Codd definiu também


uma regra base, na qual todas as doze regras foram baseadas, a Regra 0:
“Para qualquer sistema que seja anunciado como ou reivindicado a ser um
sistema de gerenciamento de banco de dados relacional, esse sistema deve
ser capaz de gerenciar bancos de dados inteiramente por meio de suas
capacidades relacionais.”

 Regra 1: A Regra da Informação.

“Todas as informações em uma base de dados relacional são


representadas explicitamente no nível lógico e por apenas uma maneira:
valores em tabelas.”

Com essa regra, Codd quis garantir que até as informações de


catálogo, como nomes das tabelas e colunas, e objetos de sistema,
estivessem armazenados em tabelas. Além disso, procurou tornar a tarefa
do administrador de manter a base de dados em um estado de integridade
geral mais simples e mais eficaz.

 Regra 2: Regra de Garantia de Acesso.

“Todo e qualquer dado (valor atômico) em uma base de dados


relacional tem a garantia de ser logicamente acessível, recorrendo a uma
combinação do nome da tabela, valor da chave primária e nome da coluna.”

Com essa regra, Codd definitivamente deixa para trás as


necessidades dos SGBDs não relacionais da época, onde havia-se a

11
necessidade de saber a forma como os dados estavam armazenados
internamente, ou seja, do usual endereçamento orientado à computador.

 Regra 3: Tratamento Sistemático de Valores Nulos.

“Valores nulos (distintos da cadeia de caracteres vazia ou uma


cadeia de caracteres em branco e distintos de zero ou qualquer outro
número) são suportados no sistema gerenciador de banco de dados
totalmente relacional, para representar informações ausentes e
informações inaplicáveis de maneira sistemática, independente do tipo de
dados.”

Técnicas anteriores exigiam a definição de um valor especial


(peculiar a cada coluna ou campo), para representar informações ausentes.
Codd quis eliminar essa premissa, pois acreditava que diminuiria a
produtividade do usuário.

 Regra 4: Catálogo On-line e Dinâmico Baseado no Modelo


Relacional.

“A descrição da base de dados (dicionário de dados – grifo nosso) é


representada no nível lógico da mesma forma que os dados ordinários, de
modo que os usuários autorizados possam aplicar a mesma linguagem
relacional à sua query que se aplica aos dados regulares.”

 Regra 5: Regra da Linguagem de Dados Compreensiva.

“Um sistema relacional pode suportar várias linguagens e vários


modos de uso de terminal. No entanto, deve haver pelo menos uma
linguagem cujas declarações sejam expressas por alguma sintaxe bem
definida, como cadeias de caracteres e abrangente em suporte a todos os
itens a seguir:

– Definição de dados e de visões.

12
– Manipulação de dados (interativo e por programa).

– Restrições de integridade.

– Autorização.

– Controle de transação (begin, commit e rollback).”

 Regra 6: Regra da Atualização de Visões.

“Todas as visualizações que são teoricamente atualizáveis, também


são atualizáveis pelo sistema.”

Com essa regra, Codd alerta para o tratamento das atualizações das
visões de dados (views).

 Regra 7: Inserções, Atualizações e Deleções de Alto Nível.

“A capacidade de lidar com uma relação base ou uma relação


derivada como um único operando, aplica-se não apenas à recuperação de
dados, mas também à inserção, atualização e exclusão de dados.”

Nesse requerimento, Codd procura proporcionar aos sistemas


gerenciadores de bancos de dados um escopo maior, para otimizar as ações
(tarefas) em tempo de execução e, ao mesmo tempo, fornecer uma
experiência mais rápida para o usuário.

 Regra 8: Independência Física dos Dados.

“Os programas de aplicativos e as atividades do terminal


permanecem logicamente inalterados sempre que forem feitas alterações
nas representações de armazenamento, ou nos métodos de acesso.”

13
 Regra 9: Independência Lógica dos Dados.

“Os programas de aplicativos e atividades de terminal permanecem


logicamente inalterados quando mudanças que preservem a informação são
feitas à essas tabelas.”

Essa regra garante que os comandos de manipulação dos dados


permaneçam inalterados quando de alterações de estruturas das tabelas,
desde que os dados originais das mesmas sejam preservados.

 Regra 10: Independência de Integridade.

“Restrições de integridade específicas de uma determinada base de


dados relacionais devem ser definidas na linguagem do banco de dados e
armazenadas no catálogo, não nos programas de aplicação.”

Com essa regra, Codd procura simplificar o desenvolvimento,


deixando a cargo do banco de dados a garantia da integridade dos dados.

 Regra 11: Independência de Distribuição.

“Um sistema gerenciador de banco de dados relacional tem


independência de distribuição.”

Por independência de distribuição, Codd quis dizer que o SGBD


relacional precisa ter uma linguagem que permita aos programas ficarem
inalterados quando uma distribuição de dados for introduzida no banco de
dados ou quando os dados forem redistribuídos.

 Regra 12: Regra de Não Subversão.

“Se um sistema relacional tiver uma linguagem de baixo nível, esse


nível não poderá ser usado para subverter ou ignorar as regras de
integridade e restrições expressas na linguagem relacional de nível
superior.”

14
Essa regra expressa a preocupação de Codd com os fornecedores de
SGBDs que estavam recodificando seus produtos como relacionais, mas que
haviam nascido com suporte a uma interface abaixo da interface de restrição
relacional, o que torna muito fácil burlar várias regras colocadas por ele,
principalmente as de restrição de integridade. Com essa subversão de baixo
nível, o banco de dados poderia passar para um status não íntegro, como
registros filhos órfãos, mesmo havendo as restrições de integridade
definidas nas tabelas do banco de dados.

Olhando para essas regras, e, em especial, para a regra de número 5


(Linguagem de Dados Compreensiva), fica clara a preocupação de Codd
para a “exigência” específica da existência de uma linguagem de alto nível
que abstraísse os detalhes internos da engine do banco de dados e do “bit-
a-bit” do armazenamento dos dados. Através dessa linguagem, os usuários
de bancos de dados relacionais conseguiriam, de forma fácil e padronizada,
criar suas estruturas de dados e manipular os dados armazenados nas
mesmas. Estava sedimentado, dessa forma, um dos pilares responsáveis
para o grande sucesso e uso em larga escala da Linguagem SQL!

1.2. História da linguagem SQL


Quando Codd publicou a teoria do Modelo de Dados Relacional, em
1970, ele era um pesquisador no laboratório da IBM, em San José.
Entretanto, com o intuito de preservar o faturamento gerado pelos produtos
“pré-relacionais”, por exemplo, o SGBD hierárquico IMS, a IBM optou
inicialmente por não implementar as ideias relacionais de Codd.

Descontente com essa situação e acreditando no salto evolutivo que


o modelo de dados relacional poderia trazer para os sistemas gerenciadores
de bancos de dados e para a história da computação, Codd procurou grandes
clientes da IBM para mostrar-lhes as novas potencialidades e benefícios da
implementação do modelo relacional. A pressão desses clientes sobre a IBM
forçou-a a incluir, no seu projeto Future Systems (FS), em andamento no

15
Centro de Pesquisas de Almaden (Almaden Research Center, na época San
Jose Research), em San José, Califórnia, o subprojeto System R.

O projeto Future Systems foi um projeto de pesquisa e


desenvolvimento realizado na IBM no início dos anos 70, com o objetivo de
desenvolver uma linha revolucionária de produtos de informática, incluindo
novos modelos de software que simplificariam o desenvolvimento de
software, explorando hardwares poderosos e modernos. Em 1974, então,
dentro do projeto Future System, iniciava-se a construção do System R, um
sistema de banco de dados experimental com o propósito de demonstrar
que as vantagens de usabilidade do modelo de dados relacional poderiam
ser implementadas em um sistema com suas funcionalidades completas e
com alto desempenho, quesitos altamente requeridos no uso cotidiano de
ambientes de produção.

Um dos resultados mais expressivos do projeto System R foi a


criação da linguagem para consulta e manipulação de dados chamada
inicialmente de SEQUEL (pronunciada como "síquel"), um acrônimo para
Structured English Query Language (Linguagem de Consulta Estruturada
em inglês). Os progenitores dessa linguagem, Donald Chamberlin e Ray
Boyce, a partir do modelo estabelecido por Codd em seu artigo “A Relational
Model of Data for Large Shared Data Banks”, desenvolveram e lançaram a
linguagem de programação em seu próprio artigo SEQUEL: A Structured
English Query Language. Eles pegaram as linguagens de Codd com o
objetivo de projetar uma linguagem relacional que fosse mais acessível aos
usuários, sem um treinamento formal em matemática ou ciência da
computação.

Essa versão original da linguagem, que continha um conjunto de


comandos que permitiam definir a estrutura de dados, inserir, atualizar,
excluir e manipular dados, foi usada inicialmente nos sistemas de bancos de
dados relacionais originais da IBM, os “System R”.

16
Entretanto, como SEQUEL era uma marca registrada pela empresa
de aeronaves Hawker Siddeley, a linguagem SEQUEL, através da eliminação
das vogais, foi renomeada para SQL (Structured Query Language -
Linguagem de Consulta Estruturada). Devido a isso, até hoje ouvimos
comumente a sigla, em inglês, ser pronunciada como "síquel" (SEQUEL), ao
invés de "és-kiú-él" (SQL), letra a letra. No entanto, em português, a
pronúncia mais comum é letra a letra: S (“esse”) - Q (“quê”) - L (“éle").

Nos anos seguintes, a SQL não se tornou disponível publicamente,


como vemos nos dias de hoje. No entanto, em 1979, a Oracle, então
conhecida como Relational Software, criou sua própria versão da linguagem
SQL chamada Oracle V2, que foi lançada comercialmente. É importante
observar que a SQL não foi a primeira linguagem de programação para
bancos de dados, mas o crescimento em larga escala da sua utilização foi
em grande parte devido à sua intuição e facilidade de uso. As linguagens de
consulta, até então, eram na maioria linguagens procedurais, o que requeria
que o usuário especificasse o caminho (navegação, posição etc.) para se
chegar ao resultado, como mostrado no pseudocódigo abaixo:

Repita para cada linha de dados:


Se a cidade for São Paulo, retorne a linha; caso contrário, não faça nada.
Mova para a próxima linha.
Final do Loop.

Já a linguagem SQL, sendo uma linguagem declarativa, requeria


apenas especificar a forma (conteúdo desejado) do resultado e não o
caminho para se chegar a ele, como mostrado no pseudocódigo abaixo:

Retorne todos os clientes cuja cidade é São Paulo.

17
De certa forma, essa peculiaridade reduziu o ciclo de aprendizado
dos desenvolvedores e administradores de bancos de dados, fazendo com
que a Linguagem SQL caísse no “gosto” rapidamente da comunidade.

Outro fator que contribuiu para a popularização da linguagem SQL,


no sentido de prover respaldo e coerência, foi a grande confiabilidade pelo
fato de Codd ter se baseado na Álgebra Relacional, e consequentemente na
Teoria de Conjuntos, para sustentar sua fundamentação teórica acerca dos
modelos de dados relacionais. Utilizando-se das já conhecidas operações da
Álgebra Relacional, como seleção, projeção e junção, e das operações da
teoria de conjuntos, como união, interseção, diferença e produto
cartesiano, Codd quase levou a comunidade ao “êxtase” ao propor uma
forma mais abstrata e natural para o armazenamento dos dados, e uma
maneira de manipulá-los mais próxima das relações humanas baseadas em
relacionamentos e correlações.

Figura 8 – Operações da Álgebra Relacional.

Fonte: Marta Mattoso.

Usando-se dos operadores de Álgebra Relacional, Codd conseguiu


fundamentar a viabilidade e usabilidade do modelo relacional e seu
armazenamento de dados no formato tabular, em tuplas. A título
informacional, pois não é o objetivo dessa disciplina aprofundar em álgebra

18
relacional, os operadores usados por Codd em sua teoria estão relacionados
na figura abaixo, e, a seguir, alguns exemplos de utilização deles.

Figura 9 – Operações/Operadores em Álgebra Relacional.

Fonte: Júnior Galvão (2016).

 Restrição (σ): retornar somente as tuplas que satisfaçam a uma

condição.

Exemplo: retornar os dados dos empregados que estão com salário


menor que 2.000.

Figura 10 – Seleção na Álgebra Relacional.

Fonte: Vania Bogorny.

19
 Projeção (π): retornar um ou mais atributos desejados. Exemplo:

retornar o nome e a idade dos empregados.

Figura 11 – Projeção na Álgebra Relacional.

Fonte: Vania Bogorny.

 Interseção (∩): retornar tuplas comuns entre duas entidades

(tabelas). Exemplo: retornar o nome e o CPF dos funcionários que


estão internados como pacientes.

π nome,CPF (FUNCIONARIO) ∩ π nome,CPF (PACIENTE)

 União (υ): retornar a união das tuplas de duas entidades (tabelas).

Exemplo: retornar o nome e o CPF dos médicos e pacientes


cadastrados no hospital.

π nome,CPF (MEDICO) υ π nome,CPF (PACIENTE)

 Diferença (-): retornar um conjunto de tuplas, que é o conjunto de

tuplas da primeira entidade, menos as tuplas existentes na segunda


entidade. Exemplo: retornar o código dos ambulatórios onde
nenhum médico dá atendimento.

π codigoA (AMBULATORIO) - π codigoA (MEDICO)

20
 Produto Cartesiano (X): retornar todas as combinações possíveis de

tuplas de duas entidades. Exemplo: retornar o nome dos médicos e


os estados onde eles podem trabalhar.

π medico,uf (MEDICO X ESTADO)

No entanto, o sucesso prolongado da SQL não pode ser atribuído


apenas às suas qualidades. A ajuda dos padrões, assunto que trataremos no
próximo capítulo, não apenas ajudou a SQL a se aproximar de um uso quase
que universal na comunidade de banco de dados, mas também acrescentou
atributos-chave que floresceram em suas especificações posteriores. Tudo
isso começou quando o American National Standards Institute (ANSI),
que é o Instituto Americano Nacional de Padrões, se envolveu.

1.3. Padronização da linguagem SQL, classes de instruções SQL e dialetos


O American National Standards Institute (ANSI) é uma organização
particular estadunidense, sem fins lucrativos, que atua há mais de 100 anos
como administradora e coordenadora do sistema norte-americano de
normas e conformidades voluntários.
Fundado em 1918 por cinco sociedades de
engenharia e três agências governamentais, o
Instituto continua sendo uma organização
privada sem fins lucrativos, apoiada por um grupo diversificado de
organizações do setor público e privado.

Ao longo de sua história, o ANSI manteve como meta principal a


melhoria da competitividade global das empresas americanas e a qualidade
de vida nos Estados Unidos, promovendo e facilitando padrões consensuais
voluntários e sistemas de avaliação de conformidade, promovendo sua
integridade. Um desses padrões, talvez o mais conhecido mundialmente
pela comunidade da computação, é o padrão publicado para a Linguagem
SQL.

21
Embora a SQL tenha sido originalmente criada pela IBM, após a sua
publicação rapidamente surgiram várias linguagens desenvolvidas pelos
fornecedores de SGBDs relacionais, cada uma com suas adaptações à
Linguagem SQL original. Por exemplo, podemos citar o dialeto PL/SQL da
Oracle. Essa expansão levou à necessidade de ser criado e adaptado um
padrão para a Linguagem SQL. Essa tarefa foi realizada, pioneiramente, pela
American National Standards Institute, em 1986, com a publicação do
padrão ANSI X3.135-1986. Este foi o começo do que as pessoas chamam
erroneamente de padrão ANSI para SQL. Na verdade, não existem padrões
ANSI, apenas padrões desenvolvidos por comitês aprovados pela ANSI,
muitos deles operando de acordo com os Requisitos Essenciais da ANSI.

Após alguns meses, ao lançamento do ANSI X3.135-1986, a


International Organization for Standardization (ISO) publicou um padrão
tecnicamente idêntico, o ISO 9075-1987, para o cenário internacional. Na
época da publicação inicial desses padrões, especificações mais detalhadas
sobre a linguagem SQL se faziam necessárias, mas o ANSI X3.135-1986
ajudou a definir as bases para alguns recursos importantes para a linguagem
de codificação. Esse padrão, por exemplo, deu a capacidade de invocar
recursos de SQL de quatro linguagens de programação: COBOL, FORTRAN,
Pascal e PL / I.

Esses padrões foram revisados em conjunto, primeiramente em


1989 (ANSI X3.135-1989 e ISO / IEC 9075: 1989) e novamente em 1992
(ANSI X3.135-1992 e ISO / IEC 9075: 1992). A edição de 1989 incluía
suporte para duas linguagens de programação adicionais, Ada e C. Essas
edições se tornaram coloquialmente conhecidas como SQL-86, SQL-89 e
SQL-92. Portanto, se você ouvir esses nomes em referência a um formato
SQL, lembre-se que ele está se referindo às várias edições desse padrão.

O padrão foi revisado novamente em 1999 (SQL3), 2003, 2008, 2011


e 2016, que continua sendo a edição atual (ISO / IEC 9075: 2016). A norma

22
internacional ISO / IEC 9075 para SQL é desenvolvida pelo ISO/IEC Joint
Technical Committee (JTC) 1 for Information Technology e desde a edição
de 2003 foi subdividida em nove partes, cada uma cobrindo um aspecto do
padrão geral, sob o título Tecnologia da Informação – Linguagens de
Banco de Dados – SQL.

Mesmo com todos esses esforços e publicações para se ter um


padrão único da Linguagem SQL, os fornecedores de SGBDs continuaram
fazendo suas próprias implementações baseadas nos padrões da
Linguagem SQL, mas com pequenas adaptações ou personalizações. Dentre
as mais conhecidas, além da já citada PL/SQL da Oracle, temos também a T-
SQL da Microsoft (usada no SQL Server) e a SQL PL da IBM.

Devido a isso, é comum encontrar algumas pequenas diferenças na


sintaxe de implementação para um mesmo tipo de comando SQL nos
diversos sistemas gerenciadores de bancos de dados relacionais
(comumente referidos pela comunidade como dialetos). Para exemplificar,
tomemos como base uma simples query SQL para retornar os N registros de
uma tabela com a cláusula TOP:

 Sintaxe de uso no SGBD (dialeto) SQL Server:

SELECT TOP [QTDE DE REGISTROS] [COLUNA(S)] FROM [TABELA]

 Sintaxe de uso nos SGBDs (dialeto) MySQL e PostgreSQL:

SELECT [COLUNA(S)] FROM [TABELA] LIMIT [QTDE DE REGISTROS]

 Sintaxe de uso no SGBD (dialeto) Oracle:

SELECT [COLUNA(S)] FROM [TABELA] WHERE ROWNUM < [QTDE


REGISTROS]

 Sintaxe de uso no SGBD (dialeto) Firebird:

SELECT FIRST [QTDE DE REGISTROS] [COLUNA(S)] FROM [TABELA]

23
Dentro do padrão ISO SQL, encontramos quatro classes (conjuntos)
de comandos da Linguagem SQL, cada uma delas com um propósito bem
definido na etapa de construção do modelo de dados físico do banco de
dados:

 Linguagem de Definição de Dados (DDL – Data Definition


Language): comandos para a criação do banco de dados e dos
objetos no banco de dados, como tabelas, índices, constraints etc., e
para alteração e exclusão de objetos.

 Linguagem de Manipulação de Dados (DML – Data Manipulation


Language): comandos para inserir, atualizar, deletar e consultar
dados.

 Linguagem de Controle de Dados (DCL – Data Control Language):


comandos para gerenciar permissões de acesso para usuários e
objetos, ou seja, permissões para executar comandos DDL, DML, DCL
e TCL.

 Linguagem de Controle de Transação (TCL – Transaction Control


Language): comandos para realizar controle das transações de
dados no banco de dados.

Figura 12 – Classes de Comandos SQL.

Fonte: http://www.learnhowtocode.info.

24
1.4. Uma “Sopa de Letras”
Siglas sempre fizeram e farão parte do cotidiano de um profissional
de TI, principalmente daqueles que se propõem a trabalhar com banco de
dados. Algumas delas já foram apresentadas nos capítulos anteriores, mas
se faz necessário apresentar algumas novas e reforçar na diferenciação de
algumas delas.

Primeiramente, é preciso estar bem clara a diferenciação entre a SQL


e o SQL. Quando se diz “a SQL”, está se fazendo menção à Linguagem SQL.
Já no segundo caso, quando se diz “o SQL”, está se fazendo menção ao SQL
Server, sistema gerenciador de banco de dados relacional desenvolvido pela
Microsoft. Adicionalmente, encontramos também o nome de outros SGBDs
fazendo menção à Linguagem SQL, de forma a indicar que são relacionais:
MySQL fornecido pela Oracle (http://www.mysql.com), PostgreSQL
desenvolvido pela PostgreSQL Global Development Group e de código
aberto (http://www.postgresql.org), SQLite desenvolvido por Richard Hipp,
sendo um banco de dados portátil e de código aberto (http://www.sqlite.org)
etc.

Outra sigla, uma das mais faladas atualmente, “NOSQL”, pode se


referenciar a duas tecnologias diferentes, mas nenhuma delas relacionadas
diretamente à Linguagem SQL. A diferença entre essas duas tecnologias é
feita na grafia: NoSQL versus NOSQL.

O termo NoSQL surgiu em 1998, quando Carlo Strozzi usou-o para


batizar um banco de dados relacional que havia desenvolvido e que não
fornecia nenhuma forma da linguagem SQL para consulta. Seu nome era
pronunciado como “nosequel”, e ele era relacional, rápido, portátil, de código
aberto que executava e interagia com o sistema operacional UNIX. Para
manipulação dos dados, ele disponibilizava “operadores” que executavam
uma única função, e o fluxo de dados era fornecido pelo próprio mecanismo
de redirecionamento de entrada/saída do UNIX. Dessa forma, cada operador

25
processava alguns dados e os transmitia ao próximo operador por meio da
função pipe do UNIX.

Os dados do NoSQL eram armazenados em arquivos ASCII UNIX e,


portanto, podiam ser manipulados por utilitários UNIX comuns, como ls, mv,
cp e editores como o 'vi'. Essa forma alternativa para manipulação dos dados,
sem a Linguagem SQL, foi o motivador do nome dado para esse banco,
NoSQL (“non SQL”), no sentido de realmente não ser um banco de dados
SQL. Entretanto, pelo fato do formato dos arquivos ser baseado em uma
relação ou tabela, com linhas e colunas, era considerado um SGBD relacional.

Figura 13 – Logo do NoSQL de Carlo Strozzi.

Fonte: Kyle Hart (1998).

Strozzi afirmava categoricamente que seu produto “nada tinha a ver


com o recém-nascido Movimento NOSQL”, e que “enquanto o primeiro é um
pacote de software bem definido, é um banco de dados relacional para todos
os efeitos e apenas intencionalmente não usa SQL como uma linguagem de
consulta; o recém-chegado (NOSQL) é principalmente um conceito (e de
nenhuma maneira novo) que se afasta do modelo relacional e, portanto,
deveria ter sido chamado mais apropriadamente de ‘NoREL’, ou algo nesse
sentido, já que não será baseado em SQL e é apenas uma consequência
óbvia de não ser relacional, e não o contrário”.

Apesar de toda a ênfase de Strozzi, Johan Oskarsson, então um


desenvolvedor na Last.fm, reintroduziu o termo NOSQL, no início de 2009,
quando organizou um evento para discutir “bancos de dados distribuídos,
não relacionais e de código aberto”. O termo tentava rotular o surgimento
de um número crescente de repositórios de dados distribuídos, não
relacionais, incluindo clones de código aberto do Google

26
Bigtable/MapReduce e do DynamoDB da Amazon. Desde então, o termo
NOSQL tem sido atribuído aos sistemas gerenciadores de bancos de dados
não relacionais (e não somente mais não SQL), que fornecem um
mecanismo de armazenamento de dados que não é baseado no formato
tabular (linhas x colunas).

Figura 14 – Logo dos SGBDs NOSQL mais usados.

Fonte: Arte dos Dados (2013).

Nessa abordagem, o termo NoSQL passou a ser escrito como NOSQL


(reparem a grafia maiúscula da letra ‘o’), para fazer menção aos SGBDs não
relacionais, “Não Apenas SQL” (‘Not Only SQL’), e objetivando enfatizar que
esses SGBDs podiam suportar outras linguagens de consulta, que não a SQL.

Figura 15 – Logo do Movimento NOSQL.

Fonte: Ylanite (2009).

Outra sigla que precisa ser diferenciada é a UnSQL, criada em 29 de


julho de 2011, quando o fundador da Couchbase e inventor do sistema
gerenciador de banco de dados CouchDB (NOSQL), Damien Katz,
juntamente com Richard Hipp, inventor do SQLite, publicaram um artigo
(‘UNQL QUERY LANGUAGE UNVEILED BY COUCHBASE AND SQLITE’,
disponível em: https://www.couchbase.com/press-releases/unql-query-
language) para anunciar o trabalho em conjunto acerca da criação de uma

27
linguagem de consulta padrão NOSQL, a UnQL (Unstructured Query
Language). Com pronúncia “Uncle”, o objetivo era que essa linguagem se
popularizasse da mesma forma que a linguagem SQL, do movimento
relacional, havia se popularizado. Foi criado até um site para o projeto
(http://unql.sqlite.org/index.html/wiki?name=UnQL), mas até o momento ela
não se popularizou e não virou um padrão ISO como a SQL.

Por fim, é preciso mencionar a sigla NewSQL, que, ao contrário do


que parece, não é uma nova versão da Linguagem SQL. Trata-se de uma nova
geração de sistemas gerenciadores de bancos de dados relacionais
distribuídos que procura fornecer o mesmo desempenho escalável de um
SGBD NOSQL distribuído ao mesmo tempo que tenta garantir todas as
propriedades ACID (Atomicidade, Consistência, Isolamento e Durabilidade)
de transações de dados dos SGBDs relacionais. Dentro dessa geração,
encontramos novos players (Amazon Aurora, CockroachDB, CosmosDB,
Google Spanner, VoltDB etc.) e SGBDs já conhecidos, mas com a engine
reformulada (MySQL Cluster, SQL Server Column Store etc.).

Figura 16 – Evolução dos SGBDs Distribuídos.

Fonte: Gustavo (2018).

28
2
Capítulo 2. Introdução ao SQL Server
2.1. Introdução ao SQL Server
Para aplicarmos na prática os conceitos e instruções da Linguagem
SQL que serão expostos nessa disciplina, utilizaremos um banco de dados
SQL Server. O Microsoft SQL Server é um sistema gerenciador de banco de
dados relacional, desenvolvido pela Microsoft, cuja primeira versão (1.0) foi
lançada em 1989. A versão atual é a 2019 (https://www.microsoft.com/pt-
br/sql-server/sql-server-2019) e será usada neste curso, no sistema
operacional Windows.

Figura 17 – Versões do SQL Server.

Versão Ano de Lançamento


2019 2019
2017 2017
2016 2016
2014 2014
2012 2012
2008 R2 2010
2008 2008
2005 2005
2000 2000
7.0 1998
6.5 1996
6.0 1995
4.2.1 1994
4.2 1992
1.1 1991
1.0 1989

Fonte: Gustavo (2020).

A título de conhecimento, além da engine de banco de dados


relacional, na família de produtos SQL Server existem outros três produtos:

 Microsoft Analysis Services (SSAS): engine analítica (OLAP) que


permite a criação de cubos e dimensões.

 Microsoft Reporting Services (SSRS): engine de exibição de dados,


que permite a criação de relatórios e dashboards.

30
 Microsoft Integration Services (SSIS): engine para extração,
transformação e carga de dados (ETL).

2.2. Conceitos básicos do SQL Server


Em linhas gerais, a macro arquitetura desses produtos pode ser
resumida como uma instância (binária) existente em um servidor, que
contém os recursos (banco de dados / pasta SSRS / catálogo SSIS), onde as
estruturas (tabelas / cubos / relatórios / pacotes SSIS) para armazenamento,
processamento e exibição dos dados são criadas, como ilustrado abaixo.

Figura 18 – Macroarquitetura de Produtos da Família SQL.

Fonte: Gustavo (2017).

2.3. Instalação do SQL Server


Para instalar o SQL Server 2019, de forma que você possa reproduzir
os exemplos expostos, realizar os exercícios e praticar, baixe o instalador
abaixo, assista à respectiva aula deste capítulo e reproduza em seu
computador.

 SQL Server 2019 Developer Edition:

– https://go.microsoft.com/fwlink/?linkid=866662.

2.4. Introdução à T-SQL


A implementação da Microsoft, no SQL Server, da Linguagem SQL
padrão ISO / IEC 9075, é chamada Transact SQL (T-SQL). A T-SQL é uma
linguagem declarativa, possui todas as opções e instruções existentes no

31
padrão ISO, como variáveis, loop, controle de fluxo e decisões, funções etc.,
além de possuir algumas instruções que não estão no padrão ISO e
instruções com sintaxe ligeiramente diferente do padrão.

Para executar queries SQL no SQL Server, utilizamos uma


ferramenta client. Client é uma interface gráfica (GUI), que permite se
conectar no banco de dados e realizar atividades, como criar bancos de
dados, tabelas, usuários, bem como manipular dados e realizar tarefas
administrativas.

A ferramenta client oficial da Microsoft, para o SQL Server, é o


Microsoft SQL Server Management Studio (SSMS), disponível para sistema
operacional Windows.

Figura 19 – SQL Server Management Studio (SSMS) 18.5.

Fonte: Gustavo (2019).

Para executar os comandos T-SQL no SQL Server, primeiramente é


necessário conectar-se ao banco de dados. No escopo deste curso e tendo
seguido os procedimentos de instalação exibidos nas aulas, para se conectar
ao SQL Server usando o Microsoft SQL Server Management Studio, basta
clicar no botão Connect mostrado na figura abaixo.

32
Figura 20 – Tela de Conexão do Management Studio 18.5.

Fonte: Gustavo (2019).

Clicando no botão New Query destacado abaixo, abrirá uma nova


área onde é possível digitar os comandos que se deseja executar.

Figura 21 – Botão para Abrir Tela de Query no SSMS 18.5.

Fonte: Gustavo (2019).

Figura 22 – Tela para Escrever e Executar Query no SSMS 18.

Fonte: Gustavo (2019).

33
Para executar a query, basta selecionar o bloco de instruções que
deseja executar (caso contrário, executará todos os comandos existentes na
janela) e clicar no botão Execute (ou usar a tecla de atalho F5).

Figura 23 – Botão para Executar Query no SSMS 18.5.

Fonte: Gustavo (2019).

Importante saber também, que os comandos T-SQL podem ser


salvos em um arquivo texto, chamado script, normalmente com a extensão
“sql”. No SSMS, isso é feito no menu File, ou nos botões de salvar da barra
de ferramentas.

Figura 24 – Salvando um Script no SSMS 18.5.

Fonte: Gustavo (2019).

34
Por fim, faz-se importante mencionar os recursos que o SSMS
fornece para trabalhar com um projeto de banco de dados, no tocante à
organização dos scripts SQL. O SSMS fornece o recurso Solução (Solution),
dentro do qual pode ser criado um ou mais Projetos de Scripts SQL Server.

Figura 25 – Criando Nova Solução e Projeto no SSMS 18.5.

Fonte: Gustavo (2019).

Esses recursos são visualizados na janela Solution Explorer do


SSMS.

Figura 26 – Janela Solution Explorer no SSMS 18.5.

Fonte: Gustavo (2019).

35
Figuras 27 e 28 – Adicionando um Projeto à Solução.

Fonte: Gustavo (2019).

Dentro de cada projeto, pode-se adicionar um ou mais scripts que já


estejam salvos em arquivos .sql, as conexões aos bancos de dados usados
por eles, ou até mesmo criar um script ou conexão, já adicionando-os ao
projeto.

Figura 29 – Adicionando Itens ao Projeto.

Fonte: Gustavo (2019).

36
Figura 30 – Exemplo de projetos e seus itens.

Fonte: Gustavo (2019).

2.5. Instalação e overview das ferramentas Client


Para instalar os clients do SQL Server 2019, de forma que você possa
reproduzir os exemplos expostos, realizar os exercícios e praticar, baixe os
instaladores abaixo, assista à respectiva aula deste capítulo e reproduza em
seu computador.

 SQL Server Management Studio 18.5 (SSMS):


https://aka.ms/ssmsfullsetup.

 Azure Data Studio (ADS):


https://go.microsoft.com/fwlink/?linkid=2135512.

2.5.1. Instalação e Overview do SQL Server Management Studio

Vide aula 2.5.1 da instalação e overview do Management Studio.

2.5.2. Instalação e Overview do Azure Data Studio

Vide aula 2.5.2 da instalação e overview do Azure Data Studio.

37
2.6. Banco de dados de exemplo AdventureWorks
Para demonstrar os comandos da Linguagem SQL, usaremos como
banco de dados de exemplo o tradicional Adventure Works, disponibilizado
pela Microsoft em https://github.com/Microsoft/sql-server-
samples/releases/tag/adventureworks e já populado com dados fictícios.
Usaremos neste curso o banco de dados AdventureWorks2019, cujo link
direto para download do backup desse banco é:

 https://github.com/Microsoft/sql-server-
samples/releases/download/adventureworks/AdventureWorks2019
.bak.

O modelo de dados para esse banco de dados pode ser encontrado


em:

 https://improveandrepeat.com/2019/02/use-the-adventureworks-
sample-database-for-your-examples.

Para fazer o restore (instalar) o banco de dados de exemplo, de forma


que você possa reproduzir os exemplos expostos, realizar os exercícios e
praticar, assista à respectiva aula deste capítulo.

38
3
Capítulo 3. Linguagem de Definição de Dados (DDL)
A Linguagem de Definição de Dados, mais comumente mencionada
como DDL (abreviação de Data Definition Language), é uma classe da
Linguagem SQL com comandos que permitem criar, alterar e excluir objetos
de banco de dados.

Dentro de um Projeto de Banco de Dados, essa classe é utilizada,


principalmente, na etapa de geração do esquema físico no banco de dados,
com base no modelo de dados físico elaborado.

Figura 31 – Modelagem de Dados.

Fonte: https://sites.google.com/site/giygiyhvhj/home/o-fatecano.

A maioria dos SGBDs fornece interface gráfica para implementação


do modelo de dados físico, mas a utilização de scripts SQL é bem útil para
questões de versionamento e validações.

40
Figura 32 – Designer Gráfico de Tabelas no SSMS.

Fonte: Gustavo (2019).

Grande parte das ferramentas CASE de modelagem de dados


também fornece recursos para a geração dos scripts DDL a partir de um
determinado modelo físico, como no exemplo abaixo de um script DDL,
gerado pela ferramenta ERWin para um modelo de dados físico no SGBD
Oracle.

Figura 33 – Script DDL.

Fonte: Gustavo (2002).

41
3.1. Criação de estruturas de dados
A criação de estruturas ou objetos, no banco de dados, é feita através
da instrução SQL CREATE. Através desse comando, consegue-se criar o
banco de dados, as tabelas, os índices, visões, chaves estrangeiras,
constraints, sinônimos, sequences etc.

Para criar um banco de dados, a sintaxe do comando SQL é:

CREATE DATABASE <Nome_do_Banco_de_Dados>;

Executando o comando SQL dessa forma, sem passar parâmetros


adicionais (como tamanho, conjunto de caracteres de idioma etc.), o banco
de dados será criado com as opções default da instância em questão.

Para exemplificar, se desejamos criar o banco de dados de nome


BDTESTE, devemos executar CREATE DATABASE BDTESTE;

Figura 34 – Exemplo de Criação de Banco de Dados.

Fonte: Gustavo (2019).

Importante ressaltar que, apesar da instrução CREATE DATABASE


pertencer ao padrão ISO da Linguagem SQL, cada SGBD implementa os
parâmetros adicionais necessários e específicos da sua plataforma no

42
comando de criação de um banco de dados, como mostrado no exemplo
abaixo entre o comando no SQL Server versus no Oracle:

Figura 35 – Create Database SQL Server x Oracle.

Fonte: Gustavo (2019).

Para criar as tabelas, que são as estruturas onde os dados são


inseridos, consultados e manipulados, usa-se o comando SQL CREATE
TABLE. No SQL Server, sua sintaxe básica é:

CREATE TABLE <Nome_da_Tabela>

column1 datatype [ NULL | NOT NULL ],

column2 datatype [ NULL | NOT NULL ], …..

);

Um exemplo de código para criar uma tabela de nome ALUNO, seria:

CREATE TABLE ALUNO

COD_ALUNO int NOT NULL,

NOM_ALUNO varchar(100) NOT NULL

43
);

Outro tipo de objeto muito comum, criado com o comando CREATE


da classe DDL da Linguagem SQL, é o sinônimo. Um objeto desse tipo
fornece um nome alternativo para outro objeto (tabela, view, função etc.) do
banco de dados. No SQL Server, sua sintaxe básica é:

CREATE SYNONYM <Nome_do_Sinônimo> FOR <Nome_do_Objeto>;

Um exemplo de código para criar um sinônimo, de nome


TB_ALUNO_NEW para a tabela de nome ALUNO, seria:

CREATE SYNONYM TB_ALUNO_NEW FOR ALUNO;

Existem várias outras possibilidades de utilização da instrução


CREATE, bem como outros comandos SQL da classe DDL, que, ao longo do
curso, serão mostrados à medida que formos aprofundando na Linguagem
SQL.

3.2 Alteração de estruturas de dados


É normal que, após a criação das estruturas de dados, surjam
necessidades de alteração delas. Na maioria das vezes, não é necessário
recriá-las para aplicar essa alteração, uma vez que a Linguagem SQL fornece
o comando ALTER para esse tipo de situação.

Com esse tipo de comando, é possível, por exemplo, desde que não
viole as regras de unicidade, adicionar uma chave primária a uma tabela já
criada, como demonstrado na sintaxe abaixo:

ALTER TABLE ALUNO

ADD CONSTRAINT PK_ALUNO PRIMARY KEY CLUSTERED

COD_ALUNO

44
);

Com o comando ALTER, é possível também adicionar uma nova


coluna a uma tabela que já esteja criada, como mostrado no exemplo abaixo:

 Adicionar Coluna COD_CURSO_FK na tabela ALUNO

ALTER TABLE ALUNO ADD COD_CURSO_FK int NULL;

Da mesma forma, desde que os dados existentes na tabela não


violem as regras de nulidade e de tipos de dados, é possível também alterar
algumas definições e propriedades de colunas já existentes em uma tabela,
como mostrado nos comandos de exemplo abaixo:

 Alterar Coluna COD_CURSO_FK Para Não Nula

ALTER TABLE ALUNO ALTER COLUMN COD_CURSO_FK int NOT NULL;

 Alterar Tamanho da Coluna NOM_CURSO

ALTER TABLE CURSO

ALTER COLUMN NOM_CURSO varchar(200) NOT NULL;

Outra possibilidade com o comando ALTER, desde que as regras de


integridade referencial dos dados não sejam violadas, é adicionar uma chave
estrangeira entre duas tabelas que já estejam criadas, como no exemplo
abaixo:

 Adicionar Chave Estrangeira COD_CURSO_FK na Tabela ALUNO

ALTER TABLE ALUNO

ADD CONSTRAINT FK_ALUNO_CURSO FOREIGN KEY

COD_CURSO_FK

45
) REFERENCES CURSO

COD_CURSO

ON UPDATE NO ACTION

ON DELETE NO ACTION;

Existem várias outras possibilidades de utilização da instrução


ALTER, e algumas delas serão utilizadas nos capítulos seguintes à medida
que formos aprofundando na Linguagem SQL.

3.3. Remoção de estruturas de dados


Um comando muito útil da linguagem SQL, também pertencente à
classe DDL, é o DROP. Com ele, é possível remover as estruturas de dados e
demais objetos de um banco de dados, devendo ser usado com muita
cautela e atenção para não remover objetos por engano.

Usando o DROP, pode-se remover banco de dados, tabelas, views,


funções, índices etc., como mostrado nos exemplos a seguir.

 Remover Sinônimo

DROP SYNONYM TB_ALUNO_NEW;

 Remover Banco de Dados

DROP DATABASE BDTESTE_DROP;

 Remover Tabela (Com FK)

DROP TABLE ALUNO;

46
Uma observação importante é quanto à remoção de alguns recursos
que não são considerados objetos independentes, como colunas de uma
tabela. Nesse caso, deve-se usar o comando ALTER, uma vez que o objeto a
ser alterado é a tabela onde a coluna se encontra, em conjunto com o
comando DROP, como demonstrado abaixo.

 Remover Coluna NOM_ALUNO da tabela ALUNO

ALTER TABLE ALUNO DROP COLUMN NOM_ALUNO;

47
4
Capítulo 4. Linguagem de Manipulação de Dados (DML)
Sem sombra de dúvidas, os comandos da linguagem SQL para
manipulação de dados, pertencentes à classe DML (Data Manipulation
Language), são os comandos mais usados em sistemas de bancos de dados
relacionais.

Inicialmente, vamos falar do comando SELECT, usado para


selecionar dados de forma a exibi-los ao usuário. Apesar de alguns
atribuírem o comando SELECT à classe DQL (Data Query Language), no
padrão ISO / IEC 9075: 2016, ele pertence à classe DML. A classe DQL
pertence a um outro padrão, menos conhecido da Linguagem SQL, chamado
ODMG, que não é o foco desse curso.

4.1. Selecionando dados


Como introduzido acima, na Linguagem SQL, a instrução utilizada
para retornar (consultar) os dados armazenados no banco de dados é o
SELECT. Essa instrução, baseada na operação de projeção da Álgebra
Relacional, retorna as colunas e seus respectivos dados no formato tabular.
Em sua estrutura mais simples (forma mínima), é composto de duas
cláusulas:

 SELECT <relação de colunas ou * >: declaração informando que o


comando se trata de uma consulta, seguida da relação de colunas
que se deseja exibir no resultado. Caso se utilize o * (asterisco) no
lugar da lista de colunas, serão retornadas todas as colunas que
existirem no objeto em questão (especificado na cláusula FROM), no
momento da execução do comando.

 FROM: origem dos dados, ou seja, o nome do(s) objeto(s) onde estão
os dados que serão selecionados.

49
Para exemplificar as duas opções existentes para formar a lista com
a relação de colunas a serem exibidas, pode-se executar no banco de dados
de exemplo AdventureWorks2017 usado nesse curso, os seguintes
comandos:

 Selecionar todas as linhas das colunas Name e ProductNumber


da tabela Product

SELECT Name, ProductNumber

FROM Production.Product;

 Selecionar todas as linhas de todas as colunas da tabela Product

SELECT *

FROM Production.Product;

Um recurso muito interessante e útil, que pode ser usado tanto para
nomes de colunas quanto de tabelas, é o alias. Com ele, é possível criar um
nome alternativo (apelido) existente apenas em tempo de execução para
cada coluna / tabela em um comando SQL.

No caso de alias de colunas, é criado usando-se a cláusula AS após


o nome da coluna, colocando-se o alias desejado em seguida, como
mostrado abaixo:

SELECT Name AS Nome_do_Produto, ProductNumber AS


Número_Produto

FROM Production.Product;

O efeito prático da utilização de alias para colunas é modificar o


cabeçalho (label) da coluna que é exibido no resultado da query, como no
exemplo abaixo:

50
Figura 36 – Alias de Coluna.

Fonte: Gustavo (2019).

Para alias de tabelas, o uso é bem mais amplo, permitindo que o alias
seja usado em outras cláusulas da instrução SELECT, como nas cláusulas
WHERE, GROUP BY, ORDER BY etc., que serão vistas mais à frente. Além
disso, a utilização de alias é muito útil nas situações em que existem colunas
com o mesmo nome em tabelas diferentes participando do mesmo comando
SQL, sendo necessário distinguir cada coluna (veremos isso mais à frente
quando falarmos de junção de tabelas).

Para se criar um alias para tabela, pode-se usar, na cláusula FROM, a


cláusula AS após o nome da tabela seguido do alias desejado, ou
simplesmente omitir a cláusula AS e colocar o alias após o nome da tabela,
como mostrado nos exemplos abaixo.

 Alias de Tabela Criado com a Cláusula AS

SELECT Name, ProductNumber FROM Production.Product AS P;

 Alias de Tabela Criado sem a Cláusula AS

SELECT Name, ProductNumber FROM Production.Product P;

Uma vez definido o alias para uma tabela, ele pode ser referenciado
na relação de colunas da cláusula SELECT, como exemplificado abaixo.

51
 Alias de Tabela nas Colunas

SELECT P.Name, P.ProductNumber FROM Production.Product P;

Obs.: ao se definir alias de tabelas, não é obrigatório usá-los na


relação de colunas, desde que não haja ambiguidade nos nomes das colunas.

Alias de tabela pode ser usado em conjunto com alias de colunas,


como mostrado no exemplo abaixo:

 Alias de Tabela + Alias de Coluna

SELECT P.Name AS Nome_do_Produto, P.ProductNumber AS


Número_Produto

FROM Production.Product P;

EXPRESSÃO CASE

Um outro recurso muito útil, que pode ser utilizado na instrução


SELECT, é a expressão CASE. Esse tipo de expressão compara um valor de
entrada a uma lista de possíveis valores correspondentes, funcionando da
seguinte maneira:

 Se uma correspondência for encontrada, o primeiro valor


correspondente será retornado como resultado da expressão CASE.
Dessa forma, múltiplas correspondências não são permitidas.

 Se nenhuma correspondência for encontrada, a expressão CASE


retorna o valor encontrado em uma cláusula ELSE, se existir.

 Se nenhuma correspondência for encontrada e nenhuma cláusula


ELSE existir, a expressão CASE retornará NULL.

No exemplo a seguir, está sendo usada a expressão CASE na coluna


ProductSubcategoryID¸ de forma que retorne o valor ‘Mountain Bikes’ se

52
o valor da coluna for igual a 1; 'Road Bikes' se for igual a 2; ‘Touring Bikes’
se for igual a 3; e 'Unknown Category' caso não seja nenhum dos três
valores.

SELECT ProductID, Name, ProductSubcategoryID,

CASE ProductSubcategoryID

WHEN 1 THEN 'Mountain Bikes'

WHEN 2 THEN 'Road Bikes'

WHEN 3 THEN 'Touring Bikes'

ELSE 'Unknown Category'

END AS SubCategoryName

FROM Production.Product;

Figura 37 – Amostra do Resultado do Exemplo de CASE

Fonte: Gustavo (2019).

4.2. Operadores aritméticos e de concatenação


Além da principal função de retornar os dados das colunas de uma
tabela, a instrução SELECT pode realizar cálculos matemáticos e
manipulações dos valores selecionados em tempo de execução. O resultado
desse processo é uma nova coluna a ser retornada pela instrução SELECT,
chamada de expressão calculada, que inicialmente não tem nome (pode-se

53
definir um alias para ela), não existe fisicamente na tabela e deve ser escalar
(retornar apenas um valor por linha).

As expressões calculadas são construídas utilizando-se operadores


aritméticos ou de concatenação, que no SQL Server são:

Para melhor exemplificar a utilização dos operadores aritméticos na


formação de uma expressão calculada, vamos ver alguns exemplos:

 Expressão Calculada Multiplicando Duas Colunas

SELECT UnitPrice, OrderQty, (UnitPrice * OrderQty) AS TotalValue

FROM Sales.SalesOrderDetail;

 Expressão Calculada Usando o Operador de Divisão e Multiplicação

SELECT UnitPrice, UnitPriceDiscount,

(UnitPriceDiscount / UnitPrice) * 100 AS DiscountPercentual

54
FROM Sales.SalesOrderDetail;

 Expressão Calculada Usando o Operador de Subtração

SELECT UnitPrice, UnitPriceDiscount,

UnitPrice - UnitPriceDiscount AS UnitPriceWithDiscount

FROM Sales.SalesOrderDetail

Importante destacar que os operadores aritméticos são usados


com colunas do tipo de dados não string (numéricos, datas, hora, moeda
etc.). Para trabalhar com strings, o operador a ser usado é o de
concatenação (+).

 Expressão Calculada Usando o Operador de Concatenação

SELECT FirstName, MiddleName, LastName,

FirstName + ' ' + MiddleName + ' ' + LastName AS NomeCompleto

FROM Person.Person;

55
Obs.: ao usar operadores, verifique primeiramente a ordem de
avalição deles no SGBD em questão. No SQL Server, por exemplo, os
operadores aritméticos e de concatenação são avaliados na seguinte ordem
(sequência):

1º  / (divisão) 4º  + (adição / concatenação)

2º  * (multiplicação) 5º  - (subtração)

3º  % (módulo)

Dessa forma, para que o operador de subtração, por exemplo, seja


avaliado primeiramente, deve-se usar parênteses, como no exemplo abaixo.
Sem os parênteses, a operação de multiplicação seria feita primeiro, para
depois fazer-se a operação de subtração:

SELECT UnitPrice, UnitPriceDiscount, OrderQty,

(UnitPrice - UnitPriceDiscount) * OrderQty AS TotalWithDiscount

FROM Sales.SalesOrderDetail;

4.3. Ordenando dados


Além das cláusulas SELECT e FROM, uma instrução SELECT pode ter
também a cláusula ORDER BY. Essa cláusula é opcional e é utilizada para
ordenar os dados retornados pela instrução SELECT.

Com relação à sintaxe, ela é a última cláusula em uma instrução


SELECT e, por default, ao utilizá-la, a ordenação é feita de forma ascendente
(A à Z, 0 à 9). Entretanto, pode-se usar as opções ASC (ascendente) ou DESC

56
(descendente, de Z a A, 9 a 0), para personalizar a ordem de exibição dos
dados.

 Classificando Ascendentemente pelo Primeiro Nome

SELECT FirstName, MiddleName, LastName

FROM Person.Person
Similar a

ORDER BY FirstName; ORDER BY FirstName ASC;

 Classificando Descendentemente pelo Primeiro Nome

SELECT FirstName, MiddleName, LastName

FROM Person.Person

ORDER BY FirstName DESC;

Figura 38 – ORDER BY ASC x ORDER BY DESC.

Fonte: Gustavo (2019).

Outra possibilidade da cláusula ORDER BY é usar mais de uma


coluna para ordenar o resultado, cada uma delas com sua ordem desejada
(ascendente ou descendente), como no exemplo abaixo.

 Classificando Ascendentemente pelo Primeiro e


Descendentemente pelo Último

57
SELECT FirstName, MiddleName, LastName

FROM Person.Person

ORDER BY FirstName ASC, LastName DESC;

Ordenação descendente pela


coluna LastName

Uma flexibilidade muito interessante dessa cláusula, é que a(s)


coluna(s) usada(s) no ORDER BY não necessariamente precisam estar na
lista de colunas da cláusula SELECT, como mostrado no exemplo a seguir.

 Ordenando por uma Coluna que não Está na Lista de Colunas


do SELECT

SELECT FirstName, MiddleName, LastName

FROM Person.Person

ORDER BY ModifiedDate ASC;

Para além disso, uma outra possibilidade que existe na cláusula


ORDER BY é usar alias de coluna para determinar a ordenação, ao invés de
usar o nome das colunas, como mostrado a seguir.

 Usando Alias de Coluna no ORDER BY

SELECT Name AS Nome_do_Produto, ProductNumber AS Número_do_Produto

FROM Production.Product

ORDER BY Nome_do_Produto ASC;

58
4.4. Filtrando dados
Além da operação de projeção da Álgebra Relacional vista até agora
(especificação das colunas a serem retornadas), a Linguagem SQL também
possui cláusulas para realizar a operação de seleção (restrição). Com essas
cláusulas, é possível restringir as tuplas (linhas/dados) retornadas pela
operação de projeção (cláusula SELECT).

A primeira delas, e a mais conhecida de todas, é a cláusula WHERE.


Em termos de sintaxe, ela é usada após a cláusula FROM e utiliza-se dos
operadores lógicos ou de comparação para filtrar os resultados retornados.

No exemplo a seguir, a cláusula WHERE está sendo usada para


retornar as colunas com o nome e a cor, somente dos produtos que sejam
da cor preta:

 Listar Produtos da Cor Preta (Black)

SELECT Name, Color

FROM Production.Product

WHERE Color = 'Black'

ORDER BY Name;

Em termos de operadores, cada SGBD procura manter o respectivo


caractere indicado no padrão ISO, mas nada impede que existam outros
operadores ou operadores representados por caracteres diferentes em
alguns SGBDs.

No SQL Server, os operadores de comparação existentes são:

Operador de Comparação Significado

= Igual a

> Maior que

59
< Menor que

>= Maior que ou igual a

<= Menor que ou igual a

<> Diferente de

!= Diferente de (não é padrão ISO)

!> Não é maior que (não é padrão ISO)

!< Não é menor que (não é padrão ISO)

Na cláusula WHERE, em conjunto com os operadores de


comparação, pode-se utilizar também os operadores lógicos, permitindo
que mais de uma condição (filtro) possa ser realizada na operação de
restrição da instrução SELECT.

No exemplo a seguir, o operador lógico OR (ou) está sendo utilizado


junto à cláusula WHERE, para retornar as informações de nome e cor
somente dos produtos que tenham/sejam da cor preta ou da cor prata:

 Listar Produtos da Cor Preta (Black) ou Prata (Silver)

SELECT Name, Color

FROM Production.Product

WHERE Color = 'Black'

OR Color = 'Silver'

ORDER BY Name;

Na prática, os operadores lógicos testam a verdade de alguma


condição, retornando um tipo de dados booleano com o valor TRUE, FALSE
ou UNKNOWN. No SQL Server, os operadores lógicos existentes são:

Operador Significado

ALL TRUE se todas as comparações forem verdadeiras

60
AND TRUE se ambas as expressões booleanas forem verdadeiras

ANY TRUE se qualquer um de um conjunto de comparações for


verdadeiro
BETWEEN TRUE se o operando/expressão estiver dentro de um intervalo

EXISTS TRUE se uma subconsulta contiver quaisquer linhas

IN TRUE se o operando for igual a um de uma lista de


valores/expressões
LIKE TRUE se o operando corresponder a um padrão

NOT Inverte o valor de qualquer outro operador booleano

OR TRUE se qualquer expressão booleana for TRUE

SOME TRUE se algumas das comparações forem verdadeiras

Nas aulas gravadas são mostrados mais exemplos acerca da


utilização dos operadores lógicos, mas por hora é preciso acrescentar que,
assim como os operadores aritméticos, os operadores lógicos e de
comparação também podem ser usados em conjunto. Dessa forma, é preciso
se atentar também à ordem de avaliação de cada um deles pelo SGBD em
questão.

No SQL Server, os operadores lógicos e de comparação são


avaliados após os operadores aritméticos e de concatenação. Entre si, os
operadores lógicos e de comparação são avaliados na seguinte ordem
(sequência):

1º  =, >, <, <=, <, !=, !, !<, !> (operadores de comparação)

2º  NOT

3º  AND

4º  ALL, ANY, BETWEEN, IN, LIKE, OR, SOME

Dessa forma, para que o operador OR, por exemplo, seja avaliado
antes do operador AND, deve-se usar parênteses, como no exemplo abaixo.
Sem os parênteses, a avaliação da expressão lógica AND seria feita primeiro,
para depois se avaliar a expressão com o operador OR:

61
 Produtos com Nome que Iniciam com 'Chain' e que Sejam da Cor
Preta ou Prata

SELECT Name,Color

FROM Production.Product

WHERE Name LIKE 'Chain%'

AND (Color = 'Black' OR Color = 'Silver')

ORDER BY Name;

 Produtos com Nome que Iniciam com 'Chain' e que Sejam da Cor
Preta, ou Todos Produtos da Cor Prata

SELECT Name,Color FROM Production.Product

WHERE Name LIKE 'Chain%'

AND Color = 'Black' OR Color = 'Silver'

ORDER BY Color;

Com relação à utilização de alias de coluna, ao contrário do que


ocorre na cláusula ORDER BY, onde é possível utilizá-lo, na cláusula WHERE
não. Isso ocorre devido ao fato da cláusula WHERE ser processada antes da
cláusula SELECT, de forma que o alias ainda não está definido quando o filtro
é aplicado.

Figura 39 – Erro ao usar alias na cláusula WHERE.

Fonte: Gustavo (2019).

62
4.4.1. Filtrando Dados com TOP / DISTINCT

Existem outras duas cláusulas, a TOP e a DISTINCT, que são muito


usadas também para filtrar dados, mas que, na prática, acabam apenas
restringindo (limitando) a quantidade de linhas ou ocorrências duplicadas
do resultado de uma instrução SELECT, respectivamente.

A cláusula TOP (N) irá atuar no resultado de uma instrução SELECT,


retornando as N primeiras linhas encontradas. No exemplo abaixo, deseja-
se retornar os cinco primeiros produtos (na ordem alfabética):

SELECT TOP (5) Name AS Nome_Produto

FROM Production.Product

ORDER BY Nome_Produto;

Importante observar que, como são


retornadas as N primeiras linhas, a cláusula
ORDER BY impacta diretamente no resultado
retornado. Por exemplo, se na query acima a
ordenação fosse decrescente (ORDER BY
Nome_Produto DESC), o resultado seria como mostrado ao lado.

Já a cláusula DISTINCT irá atuar na eliminação dos resultados


repetidos retornados (tuplas / linhas repetidas) pela instrução SELECT onde
ela for usada. No exemplo abaixo, deseja-se saber as cores de produtos
existentes (sem necessidade de retornar cores repetidas).

SELECT DISTINCT Color AS Cores_de_Produtos

FROM Production.Product

WHERE Color IS NOT NULL

ORDER BY Cores_de_Produtos;

63
Importante observar que a cláusula DISTINCT atua em todas as
colunas da cláusula SELECT. Caso exista mais de uma coluna no SELECT,
basta apenas uma cláusula DISTINCT, uma vez que o que será eliminado
será a ocorrência duplicada da combinação das colunas, ou seja, as tuplas
duplicadas. No exemplo abaixo, incluindo a coluna nome do produto, o efeito
da cláusula DISTINCT será retornar as ocorrências não repetidas da
combinação das colunas Color e Name.

SELECT DISTINCT Color AS Cores_de_Produtos, Name AS Nome_Produto

FROM Production.Product

WHERE Color IS NOT NULL

ORDER BY Color, Name;

4.5. Funções de caracteres, de data e hora


Funções de caracteres são recursos de programação da Linguagem
SQL utilizados para modificar ou realizar um tratamento específico em uma
cadeia de caracteres (string). Nos SGBDs, essas funções já vêm prontas
para serem utilizadas junto às queries SQL, sendo conhecidas como built-in
string functions.

Essas funções podem receber como parâmetro de entrada uma


string, uma coluna ou uma expressão, e retornam os dados
alterados/tratados em um formato do tipo texto. Quando as funções de
caracteres recebem parâmetros que não são do tipo string, os dados de
entrada são implicitamente convertidos em um tipo de dados texto, de
forma que a ação desejada possa ser executada.

Obs.: mais informações sobre tipos de dados do SQL Server podem


ser vistas na documentação do produto, disponível em:

64
https://docs.microsoft.com/pt-br/sql/t-sql/data-types/data-types-transact-
sql?view=sql-server-2017.

Cada uma das funções de caracteres possui sua sintaxe específica e,


no SQL Server, as mais utilizadas são:

 LOWER (string): converte a string passada como parâmetro em


caracteres minúsculos.

Figura 40 – Função LOWER com cadeia de caracteres.

Fonte: Gustavo (2019).

 UPPER (string): converte a string passada como parâmetro em


caracteres maiúsculos.

Figura 41 – Função UPPER em Colunas.

Fonte: Gustavo (2019).

 SUBSTRING (string, posição, quantidade): retorna parte da string a


partir da posição especificada até a quantidade de caracteres
informada.

65
Figura 42 – Função SUBSTRING.

Fonte: Gustavo (2019).

 LEFT (string, quantidade): retorna a parte mais à esquerda de uma


string, contendo a quantidade de caracteres informada.

Figura 43 – Função LEFT.

Fonte: Gustavo (2019).

 RIGHT (string, quantidade): retorna a parte mais à direita de uma


string, contendo a quantidade de caracteres informada.

Figura 44 – Função RIGHT.

Fonte: Gustavo (2019).

66
 LEN (string): retorna a quantidade de caracteres encontrados na
string, excluindo espaços à direita.

Figura 45 – Função LEN.

Fonte: Gustavo (2019).

 DATALENGTH (string): retorna a quantidade de caracteres


encontrados na string, incluindo espaços à direita.

Figura 46 – Função DATALENGTH.

Fonte: Gustavo (2019).

 CHARINDEX (string_a_encontrar, string_onde_procurar, [início]):


procura uma string a ser encontrada em uma outra string onde a
busca deve ser feita, retornando a posição inicial na string onde foi
feita a busca (se encontrada). Opcionalmente, pode-se especificar a
posição de início a partir da qual a busca na string deve ser feita.

Figura 47 – Função CHARINDEX.

Fonte: Gustavo (2019).

67
 REPLACE (string, string_a_encontrar, string_substituta): substitui,
na string alvo da busca, todas as ocorrências de uma string a ser
encontrada, pelo valor de uma string substituta informada.

Figura 48 – Função REPLACE.

Fonte: Gustavo (2019).

 REPLICATE (string, quantidade): repete uma string por uma


quantidade especificada de vezes.

Figura 49 – Função REPLICATE.

Fonte: Gustavo (2019).

 REVERSE (string): retorna a ordem inversa de uma string.

Figura 50 – Função REVERSE.

Fonte: Gustavo (2019).

 LTRIM (string): remove todos os espaços à esquerda da string.

68
Figura 51 – Função LTRIM.

Fonte: Gustavo (2019).

 RTRIM (string): remove todos os espaços à direita da string.

Figura 52 – Função RTRIM.

Fonte: Gustavo (2019).

 TRIM (string): remove todos espaços do início ou final de uma


string.

Figura 53 – Função TRIM.

Fonte: Gustavo (2019).

 TRIM (‘caracteres’ FROM string): remove os espaços e os caracteres


especificados do início (antes do espaço) ou do final (depois do
espaço) da string em questão.

Figura 54 – Função TRIM com FROM.

Fonte: Gustavo (2019).

69
 CONCAT (string, string_1, string_N): concatena uma ou mais
strings.

Figura 55 – Função CONCAT.

Fonte: Gustavo (2019).

Para além disso, as funções de caracteres podem ser usadas em


conjunto, com a saída (retorno) de uma determinada função, sendo o
parâmetro de entrada de outra função. No exemplo a seguir, a função
CONCAT concatena três colunas e as passa como parâmetro de entrada para
a função UPPER, que converte a string inteira para letras maiúsculas,
passando-a como parâmetro de entrada para a função REPLACE, que, por
sua vez, substitui os espaços por underline “_”.

Figura 56 – Funções de Caracteres Usadas em Conjunto.

Fonte: Gustavo (2019).

Figura 57 – Tabela Resumo de Funções de Caracteres.

Função Ação

LOWER Converte a string em caracteres minúsculos.

70
UPPER Converte a string em caracteres maiúsculos.

SUBSTRING Retorna uma parte da string.

Retorna a parte esquerda de uma string com a quantidade especificada


LEFT
de caracteres.

Retorna a parte direita de uma string com a quantidade especificada de


RIGHT
caracteres.

Retorna a quantidade de caracteres encontrados na string, excluindo


LEN
espaços à direita.

Retorna a quantidade de caracteres encontrados na string, incluindo


DATALENGTH
espaços à direita.

Procura uma string dentro de uma segunda string, retornando à posição


CHARINDEX
inicial da primeira expressão, se encontrada.

REPLACE Substitui todas as ocorrências de um valor por outro valor.

REPLICATE Repete uma string por um número especificado de vezes.

REVERSE Retorna a ordem inversa de uma string.

Retorna uma string, resultante da concatenação (junção) de duas ou


CONCAT
mais strings, de ponta a ponta.

Remove o caractere de espaço ou outros caracteres especificados do


TRIM
início ou final de uma string.

LTRIM Trunca todos os espaços à esquerda.

RTRIM Trunca todos os espaços à direita.

Fonte: Gustavo (2019).

71
Funções de data e hora:

Uma outra categoria de built-in functions, específica para se


trabalhar com os tipos de dados de data/hora, é a de funções de data e hora.
Com essas funções, é possível extrair partes dos campos de data/hora,
alterá-los para um determinado formato, bem como realizar operações de
cálculo.

Obs.: o SQL Server (e a grande maioria dos SGBDs) não oferece meios
para que sejam inseridas datas e horas como valores literais. Dessa forma, é
necessário usar sequências de caracteres (strings literais) delimitadas com
aspas simples, seguindo-se o formato* de data e hora especificado nas
configurações regionais do sistema operacional. Com isso, o SQL Server
consegue converter, fidedignamente, as strings literais em data e hora.

* Formato Brasileiro: ‘DD-MM-AAAA hh:mm:ss[.nnnnnnn]’

Formato Americano: ‘YYYY-MM-DD hh:mm:ss[.nnnnnnn]’

A / Y  ano
M  mês
D  dia

h  hora
m  minuto
s  segundos

nnn  milisegundos
nnnnnmicrosegundos
nnnnnnnnanosegundos

72
As funções mais básicas na Linguagem SQL para se trabalhar com data e hora
são as funções que retornam parte da informação de um dado do tipo data e/ou hora.
A seguir, são listadas as principais funções básicas de data e hora disponíveis no SQL
Server, com um exemplo envolvendo todas elas ao final.

 DAY (data): retorna um inteiro representando o dia da data.

 MONTH (data): retorna um inteiro representando o mês da data.

 YEAR (data): retorna um inteiro representando o ano da data.

 Separando Dia, Mês e Ano de um Campo com Data e Hora (datetime)

SELECT DISTINCT DueDate AS Data_e_Hora_Vencimento,


DAY(DueDate) AS Dia_Vencimento,
MONTH(DueDate) AS Mês_Vencimento,
YEAR(DueDate) AS Ano_Vencimento
FROM Purchasing.PurchaseOrderDetail
ORDER BY DueDate DESC;

Figura 58 – Resultado exemplo de funções de data e hora.

Fonte: Gustavo (2019).

Alternativamente a essas funções, pode-se usar a função


DATENAME, que além de retornar o dia, mês e ano de uma data-hora, pode
retornar outras partes/informações, como o dia da semana, o nome por
extenso do mês, a hora, minutos, segundos etc.

73
Sua sintaxe é DATENAME (datepart, date), onde datepart são as
opções abaixo, e date é um campo ou uma cadeia de caracteres no formato
do tipo data-hora.

Figura 59 – Opções datepart para funções de data e hora.

datepart Informação extraída Exemplo do retorno

year, yyyy, yy Ano 2019

month, mm, m Mês October

dayofyear, dy, y Dia do ano 303

day, dd, d Dia do mês 30

week, wk, ww Número da semana 44

weekday, dw Dia da semana Tuesday

hour, hh Hora 12

minute, n Minutos 15

second, ss, s Segundos 32

millisecond, ms Milissegundos 123

microsecond, mcs Microssegundos 123456

nanosecond, ns Nanosegundos 123456700

Fonte: Gustavo (2019).

 Listando Dia da Semana, Hora e Minutos

SELECT DATENAME (weekday,GETDATE()) AS Dia_da_Semana,

DATENAME (hour,GETDATE()) AS Hora,

DATENAME (n,GETDATE()) AS Minutos;

Duas funções também muito interessantes, que possibilitam


calcular a diferença entre duas datas, ou fazer uma adição (de dias, horas,
minutos etc.), são as funções DATEDIFF e DATEADD, respectivamente.
Ambas utilizam as opções de datepart, listadas na Figura 59, para indicar a
unidade de medida da diferença a ser retornada (no caso de DATEDIFF), ou
a unidade da medida do valor que está sendo somado à data (no caso de

74
DATEADD). A seguir, são mostradas as sintaxes e exemplos para cada uma
delas.

 DATEDIFF (datepart , Data_Inicial , Data_Final):

 Calcular diferença em dias entre duas datas

SELECT DATEDIFF(day, '2018-12-31 23:59:59', '2019-01-01 00:00:00');  1

SELECT DATEDIFF(day, '2018-12-31', '2019-01-07');  7

SELECT DATEDIFF(day, '2018', '2019');  365

 Calcular diferença em horas entre duas datas

SELECT DATEDIFF(hour, '2018-12-31 23:59:59', '2019-01-01 00:00:00');  1

SELECT DATEDIFF(hour, '2018-12-31', '2019-01-01');  24

SELECT DATEDIFF(hour, '2018', '2019');  8.760

 Calcular diferença em minutos entre duas datas

SELECT DATEDIFF(minute, '2018-12-31 23:59:59', '2019-01-01 00:00:00');  1

SELECT DATEDIFF(minute, '2018-12-31', '2019-01-01');  1.440

SELECT DATEDIFF(minute, '2018', '2019');  525.600

 DATEADD (datepart , Quantidade , Data):

 Adicionar 1 hora a uma data

SELECT DATEADD (hour, 1, '2019-01-01 00:30:00');

Resultado  ‘2019-01-01 01:30:00.000’

 Adicionar 2 horas a uma data

SELECT DATEADD (hour, 2, '2019-01-01 22:30:00');

75
Resultado  ‘2019-01-02 00:30:00.000’

 Adicionar 6 meses a uma data

SELECT DATEADD (month, 6, '2019-01-15');

Resultado  ‘2019-07-15 00:00:00.000’

4.6. Tipos de dados e conversões Explícitas x Implícitas


Além da conversão implícita de strings literais, no formato de
data/hora para o tipo de dados datetime, o SQL Server realiza outras
conversões implícitas de forma totalmente transparente para o usuário. As
mais comuns acontecem quando são feitas comparações entre dois tipos de
dados diferentes, como quando um smallint é comparado a um int, e o
smallint é implicitamente convertido para int antes que a comparação
prossiga.

Outra conversão implícita muito comum é feita na atribuição de


valores a uma variável ou a uma coluna. Nesse caso, o tipo de dados
resultante é o definido na declaração da variável ou o da coluna. Por
exemplo, no código abaixo, a variável Texto é definida com o tipo varchar, é
atribuído um valor do tipo int a ela e, em seguida, feita uma concatenação
dessa variável com uma string. Como consequência, o valor inteiro 10 é
convertido implicitamente em um varchar, retornando, na instrução
SELECT, uma string de caracteres.

Figura 60 – Exemplo de Conversão Implícita.

Fonte: Gustavo (2019).

76
Obs.: para operadores de comparação ou outras expressões, o tipo
de dados resultante depende das regras de precedência do tipo de dados de
cada SGBD. As do SQL Server podem ser encontradas em:

 https://docs.microsoft.com/pt-br/sql/t-sql/data-types/data-type-
precedence-transact-sql?view=sql-server-2017.

Além das conversões implícitas, é possível fazer também conversões


explícitas usando-se funções padrões da Linguagem SQL. Na T-SQL, são
disponibilizadas as funções CAST() e CONVERT(), sendo a primeira do
padrão ISO.

Figura 61 – Exemplo de conversão explícita de dados.

Fonte: Gustavo (2019).

A grande maioria dos SGBDs fornece um mapa como o mostrado


abaixo, indicando as conversões implícitas e explícitas permitidas entre os
tipos de dados existentes no produto, bem como as conversões não
possíveis.

77
Figura 62 – Mapa de conversões de tipos de dados.

Fonte: Microsoft (2017).

78
5
Capítulo 5. Agrupamento de Dados e Funções de Agregação
Em muitas situações, pode haver a necessidade de agrupar dados
em conjuntos ou executar um cálculo (contagem, soma, média etc.) em um
conjunto de linhas, ao invés de fazê-lo linha a linha. Para isso, a Linguagem
SQL disponibiliza cláusulas para agrupamento de dados, como a GROUP BY
e as funções de agregação.

5.1. Funções de agregação


Nesse tipo de função, os valores de várias linhas são agrupados para
formar um único valor resumido (agregado), sendo muito útil para consultas
analíticas e cálculos matemáticos.

Antes de se começar a trabalhar com funções de agregação, é


preciso estar bem claro que:

 Funções agregadas retornam um valor único (escalar) e podem ser


usadas nas instruções SELECT.

 Com exceção da função COUNT(*), as funções agregadas ignoram


valores nulos (NULL).

 Funções agregadas não geram um alias de coluna, sendo permitido


defini-lo explicitamente.

 Funções agregadas operam em todas as linhas retornadas pela


instrução SELECT (respeitando, é claro, os filtros definidos na
cláusula WHERE).

 Se não existir uma cláusula GROUP BY (que será vista mais adiante),
não pode existir colunas na cláusula SELECT que não estejam em
uma função agregada.

80
As funções de agregação da Linguagem SQL estão presentes na
grande maioria dos SGBDs. No SQL Server, algumas das mais usadas são:

 MIN (expressão): retorna o menor número, data/hora mais antiga


ou a primeira ocorrência de uma string.

 MAX (expressão): retorna o maior número, data/hora mais recente


ou última ocorrência de uma string.

--Usando as funções MIN e MAX

SELECT MIN(UnitPrice) AS Preço_Mínimo, MAX(UnitPrice) AS


Preço_Máximo

FROM Sales.SalesOrderDetail;

 COUNT ( * ) ou COUNT (expressão): com (*), conta todas as linhas,


incluindo aquelas com valores nulos (NULL). Quando uma coluna é
especificada como <expressão>, retorna a contagem de linhas não
nulas para essa coluna, como demonstrado no exemplo abaixo.

Figura 63 – COUNT (*) x COUNT (expressão).

Fonte: Gustavo (2019).

 SUM (expressão): soma todos os valores numéricos não nulos de


uma coluna.

 AVG (expressão): calcula a média de todos os valores não nulos


retornados, ou seja, é o resultado de SUM / COUNT.

81
Figura 64 – Funções SUM e AVG.

Fonte: Gustavo (2019).

Uma opção muito interessante, presente na maioria dos SGBDs, é a


de se utilizar funções de agregação em conjunto com as outras funções
vistas anteriormente (funções de data e hora, de caracteres etc.), como
demonstrado no exemplo abaixo.

Figura 65 – Funções de agregação em conjunto com outras.

Fonte: Gustavo (2019).

Outro recurso muito útil de ser utilizado em conjunto com as funções


agregadas é a cláusula DISTINCT. Quando usada com uma função de
agregação, o DISTINCT remove valores duplicados de uma coluna antes de
calcular o valor final. Com isso, é possível agregar ocorrências únicas dos
valores de uma coluna, como no exemplo abaixo, onde conta-se as compras
feitas por clientes diferentes.

82
Figura 66 – DISTINCT com funções de agregação.

Fonte: Gustavo (2019).

Para além disso, é muito importante ter em mente o comportamento


das funções de agregação com relação a valores nulos, de forma a não serem
feitos cálculos errados ou obter-se resultados inesperados. Como informado
anteriormente, com exceção da função COUNT(*), todas as funções de
agregação ignoram valores nulos. Isso significa que, ao usar a função SUM,
por exemplo, ela somará apenas valores não nulos, uma vez que valores
nulos não são avaliados como zero.

Estando isso exposto, pode-se notar, no exemplo abaixo, o cálculo


da média dos pesos dos produtos sendo calculado de forma errada ao usar
COUNT(*), uma vez que a coluna que contém essa informação (weight)
contém valores nulos.

Figura 67 – Valores nulos em funções de agregação.

Fonte: Gustavo (2019).

Para se tratar de valores nulos em tempo de execução, a Linguagem


SQL fornece funções para substitui-los por valores válidos. No SQL Server,
temos a função COALESCE para esse propósito, devendo-se passar como
parâmetros para ela a coluna e o valor com o qual os valores nulos devem

83
ser substituídos. Dessa forma, podemos fazer a média do exemplo acima de
forma correta, tratando os nulos antes, como mostrado no exemplo abaixo.

Figura 68 – Tratando Valores Nulos com COALESCE.

Fonte: Gustavo (2019).

5.2. Agrupamentos de dados


Em vários momentos em um projeto de banco de dados,
principalmente em projetos de caráter analítico, surgem necessidades para
agrupar os dados retornados por uma query em grupos ou subconjuntos. Na
maioria delas, fazer a sumarização de dados somente após esse
agrupamento se faz essencial para as regras de análise dos dados.

Como exemplos de agrupamento com sumarização de dados,


podemos citar uma query que retorne o total de vendas agrupado por dia,
por produto ou por vendedor, bem como uma query que retorne os limites
mínimos e máximos de preço em cada categoria de produtos. Na Linguagem
SQL, a cláusula responsável por prover essa possibilidade é a GROUP BY. Em
termos de sintaxe, ela é inserida após a cláusula FROM ou após a cláusula
WHERE (quando há um filtro na query).

SELECT < lista de colunas / expressões >

FROM < tabela >

WHERE < condição de filtro – opcional >

GROUP BY < lista de colunas / expressões >

84
ORDER BY < lista de colunas / expressões – opcional >

Dessa forma, a cláusula GROUP BY criará grupos e agrupará as linhas


em cada grupo, conforme determinado pelas combinações exclusivas dos
elementos (uma coluna/múltiplas colunas/expressões) especificados na
cláusula. A título de exemplo, na query abaixo está sendo contabilizado o
total de vendas agrupadas pelo ID do funcionário (ID NULL significa
compras feitas pela Web, sem vendedor).

Figura 69 – Exemplo de GROUP BY Simples.

Fonte: Gustavo (2019).

Um ponto de atenção muito importante ao se trabalhar com


agrupamentos na Linguagem SQL refere-se às situações em que é exibido o
erro abaixo*.

Figura 70 – Erro de GROUP BY.

Fonte: Gustavo (2019).

Esse erro acontece devido à ordem lógica de processamento das


operações (cláusulas) nos SGBDs. No SQL Server, como mostrado no quadro

85
abaixo, a cláusula GROUP BY é processada antes do SELECT. Isso significa
que, se uma coluna ou expressão não estiver presente no GROUP BY ou não
estiver em uma função de agregação, ela não fará parte do conjunto de
dados (colunas) passado para a cláusula SELECT, no qual ela agirá
selecionando as colunas especificadas e que estejam disponíveis, ou seja,
que foram passadas pelas cláusulas anteriores.

Ordem Lógica das Operações Cláusula

5 SELECT
1 FROM
2 WHERE
3 GROUP BY
4 HAVING
6 ORDER BY

*Código correto: SELECT SalesPersonID AS ID_do_Vendedor,

OrderDate AS Ano_da_Venda,

COUNT(SalesOrderID) AS Total_de_Vendas

FROM Sales.SalesOrderHeader

GROUP BY SalesPersonID, OrderDate

ORDER BY OrderDate DESC;

Em decorrência dessa mesma ordem lógica de processamento, não


é possível utilizar um alias definido na cláusula SELECT, na cláusula GROUP
BY, uma vez que no momento do processamento da cláusula GROUP BY, o
alias ainda não foi processado (será definido somente quando a cláusula
SELECT for processada).

86
Figura 71 – Erro ao tentar usar alias no GROUP BY.

Fonte: Gustavo (2019).

5.2.1. Filtrando agrupamentos de dados

Outra característica, também devida à ordem lógica de


processamento, diz respeito à realização do filtro da cláusula WHERE antes
do conjunto de dados ser passado para a etapa de agrupamento, ou seja, da
execução da cláusula GROUP BY. Dessa forma, ao contrário do que pode
parecer, a cláusula WHERE não tem a capacidade de filtrar os grupos
propriamente ditos, fazendo apenas o papel de filtro dos dados (tuplas) que
serão agrupados na etapa posterior de execução da cláusula GROUP BY (o
que pode ou não reduzir a quantidade de grupos exibidos).

No exemplo a seguir, podemos constatar que, na etapa de


processamento da cláusula WHERE, todas as vendas diárias que não são do
ano de 2013 (filtro YEAR(OrderDate)=’2013) não são passadas para a etapa
de agrupamento. Dessa forma, na etapa de processamento da cláusula
GROUP BY, os valores de todas as vendas do ano de 2013 são agrupados
(sumarizados) por dia (GROUP BY OrderDate).

87
Figura 72 – Ordem de execução do WHERE com GROUP BY.

Fonte: Gustavo (2019).

Devido a isso, a Linguagem SQL disponibiliza uma cláusula


específica para possibilitar o filtro de agrupamentos de dados: a cláusula
HAVING. Com ela sendo processada após a cláusula GROUP BY, e
consequentemente após a cláusula WHERE, é possível filtrar os grupos
usando inclusive o resultado das funções de agregação. Dessa forma, é
muito importante ter claro em mente que a cláusula HAVING só opera (atua)
nos grupos formados pela cláusula GROUP BY.

Sua sintaxe é muito semelhante à da cláusula WHERE, sendo


possível utilizar também todos os operadores de comparação vistos
anteriormente:

SELECT < lista de colunas / expressões >

FROM < tabela >

WHERE < condição de filtro – opcional >

88
GROUP BY < lista de colunas / expressões >

HAVING < condição de filtro de grupos – opcional >

ORDER BY < lista de colunas / expressões – opcional >

Assim sendo, usando a mesma query do exemplo da Figura 71 e


incluindo a cláusula HAVING para filtrar e exibir somente os grupos de dias
com vendas superiores a 4 milhões, no ano de 2013, teríamos a seguinte
ordem de execução:

Figura 73 – Ordem de execução do HAVING com GROUP BY.

Fonte: Gustavo (2019).

Importante esclarecer que o uso das funções de agregação, na


cláusula HAVING, não é obrigatório, bem como é possível usar as cláusulas
WHERE e HAVING em conjunto. Entretanto, as colunas a serem usadas
como filtro, na cláusula HAVING, precisam estar definidas na cláusula
GROUP BY ou estarem sendo usadas em uma função de agregação. Outro
ponto importante, e que também está relacionado com a ordem de execução
das cláusulas, é em relação à impossibilidade do uso de alias na cláusula
HAVING, visto que ela é processada antes da cláusula SELECT onde o alias
é definido.

89
6
Capítulo 6. Junção de Tabelas (JOIN)
6.1. Introdução à Junção de Tabelas
A junção de tabelas está intrinsicamente inserida na teoria de banco
de dados relacional, onde uma tabela pode estar relacionada a uma ou mais
tabelas. Dessa forma, a Linguagem SQL vem prover, em termos de cláusulas
e instruções, os recursos necessários para fazer esse relacionamento entre
duas ou mais tabelas, ou seja, o famoso JOIN (junção).

Antes de adentrarmos as cláusulas e mecanismos para se fazer a


junção entre tabelas, é preciso lembrar que esse recurso (join entre tabelas)
está diretamente relacionado com a Teoria de Conjuntos, onde elementos
de um conjunto estão relacionados com elementos de outro conjunto, como
mostrado nos exemplos abaixo.

Figura 74 – Relacionamento 1x1.

Figura 75 – Relacionamento 1xN.

Fonte: Gustavo (2019).

Até agora, as queries que foram vistas não estavam considerando o


relacionamento (join) entre as tabelas, ou seja, eram queries em apenas uma
tabela (um conjunto de dados), como mostrado no exemplo abaixo.

91
Figura 76 – Queries sem Join.

Fonte: Concurso INEP/ENADE (2017).

Na teoria de banco de dados relacional, para se realizar um


relacionamento entre as tabelas, são usados os recursos de chave
primária/secundária e chave estrangeira (foreign key). Dessa forma, a coluna
de uma tabela é comparada com a coluna de outra tabela, construindo-se o
elo desejado (tipos de joins que serão vistos mais à frente) entre elas.

A título de exemplo, suponha que tenhamos duas tabelas


(conjuntos), como os mostrados abaixo, de Categoria de Produtos e Sub
Categoria de Produtos:

Figura 77 – Relacionamento Entre Dois Conjuntos.

Fonte: Gustavo (2019).

Olhando para o modelo relacional, teríamos algo como a figura


mostrada abaixo, onde a chave primária da tabela de categoria de produtos
é chave estrangeira na tabela de subcategorias de produtos (uma categoria
de produtos tem uma ou mais subcategorias de produtos).

92
Figura 78 – Modelo Relacional.

Fonte: Gustavo (2019).

Com isso, para recuperarmos a lista de categorias de produtos e suas


respectivas subcategorias, é necessário fazer um relacionamento entre
essas duas tabelas. Um dos meios mais antigos e simples para se fazer essa
operação é usando o operador de comparação “=” (padrão ANSI SQL-89),
como mostrado no exemplo abaixo.

Figura 79 – Exemplo de JOIN com Operador de Comparação.

Fonte: Gustavo (2019).

Perfeitamente factível também realizar o join entre mais de duas


tabelas, como mostrado no exemplo abaixo, onde deseja-se listar os

93
produtos e suas respectivas categorias e subcategorias. Perceba que para
fazer o join entre mais de duas tabelas com o operador de comparação “=”,
faz-se necessário usar em conjunto o operador lógico “AND”.

Figura 80 – Exemplo de JOIN entre três tabelas.

Fonte: Gustavo (2019).

Para melhorar a visibilidade do código, deixando a query mais limpa,


pode-se usar o recurso de alias tanto para as tabelas quanto para as colunas.
Para o exemplo mostrado na Figura 80, o código ficaria da seguinte forma:

SELECT P.Name AS Nome_do_Produto,


S.Name AS Nome_da_SubCategoria,
C.Name AS Nome_da_Categoria
FROM Production.Product P, Production.ProductCategory C,
Production.ProductSubCategory S
WHERE P.ProductSubCategoryID = S.ProductSubcategoryID
AND C.ProductCategoryID = S.ProductCategoryID
ORDER BY Nome_do_Produto ASC;

Ao se trabalhar com queries multitabelas, é muito importante


conhecer o conceito de produto cartesiano e evitá-lo, uma vez que é muito
oneroso para o servidor, em termos de consumo de recurso (CPU, memória
RAM e I/O de disco). Produto cartesiano é um conceito da Teoria de

94
Conjuntos, consistindo no produto entre dois conjuntos. Dessa forma, se
temos um conjunto com cinco itens e outro conjunto com seis itens, o
produto cartesiano entre eles conterá 30 itens (5 x 6).

Em banco de dados relacional, um produto cartesiano ocorre quando


tabelas são relacionadas em uma query sem se considerar qualquer relação
lógica entre elas, ou seja, sem a cláusula/expressão do join. Em outras
palavras, isso corresponde a não existência da cláusula WHERE,
comparando-se os campos entre as tabelas. No exemplo da Figura 79, para
gerar um produto cartesiano bastaria retirar a cláusula WHERE, como
mostrado na figura abaixo. Sem informações sobre o relacionamento entre
as tabelas, o processador de consultas do SQL Server exibirá todas as
combinações possíveis de linhas, ou seja, todas as linhas da tabela de
categoria serão relacionadas com todas as linhas da tabela de subcategoria.

Figura 81 – Exemplo de Produto Cartesiano (ANSI SQL-89).

Fonte: Gustavo (2019).

6.2. INNER JOIN, CROSS JOIN e OUTER JOIN


No capítulo anterior, vimos a sintaxe para fazer join entre as tabelas
usando a sintaxe do padrão ANSI SQL-89 com o operador “=”. Esse tipo de
join é chamado, na Linguagem SQL, de INNER JOIN, e significa dizer que,

95
para as linhas serem retornadas, os valores das colunas das tabelas
relacionadas devem ser iguais. Na Teoria de Conjuntos, isso representa a
operação de interseção entre dois conjuntos. Na revisão ANSI SQL-92,
foram introduzidas, na Linguagem SQL, as cláusulas específicas para cada
tipo de join, de forma a deixar as operações na cláusula WHERE apenas para
os filtros desejados, e também de forma a evitar produtos cartesianos (mais
fáceis de acontecer usando-se somente o operador “=”).

Dessa forma, para realizar um INNER JOIN entre duas tabelas, ou


seja, uma operação de interseção, a sintaxe que pode ser usada, a partir do
padrão ANSI SQL-92, é a mostrada na figura abaixo.

Figura 82 – INNER JOIN (ANSI SQL-92).

Fonte: Concurso INEP/ENADE (2017).

Usando essa nova sintaxe no exemplo mostrado no capítulo anterior


na figura 79 (que usava o operador “=”), a query ficaria como a mostrada
abaixo:

Como resultado do processamento dessa query, todas as linhas de


ambas as tabelas, que não satisfazerem à cláusula do join
(ProductCategory.ProductCategoryID =
ProductSubCategory.ProductCategoryID), não serão retornadas.

96
Obs.: assim como na sintaxe ANSI SQL-89, usando-se o operador de
comparação “=”, a ordem em que as tabelas são escritas em uma query com
INNER JOIN, bem como a ordem que as comparações são feitas, não
impactam no resultado da consulta. Da mesma forma que na sintaxe do
padrão ANSI SQL-89 é perfeitamente factível realizar join entre mais de
duas tabelas, usando-se a sintaxe da Linguagem SQL a partir do padrão
ANSI SQL-92, como mostrado a seguir, onde o exemplo da Figura 80 foi
adaptado para usar a cláusula INNER JOIN.

Outro tipo de join que pode ser feito tanto usando a sintaxe ANSI
SQL-89 quanto a sintaxe ANSI SQL-92, é o SELF INNER JOIN. Esse tipo de
join nada mais é que o join de uma tabela com ela mesma, que ocorre muito
frequentemente em tabelas que representam hierarquias ou quando deseja-
se fazer correlações entre as linhas da mesma tabela. Um ponto importante
é que esse tipo de join só é possível com a utilização de alias para a tabela,
uma vez que o nome das tabelas relacionadas será o mesmo. No exemplo
abaixo, com a sintaxe SQL-92, deseja-se listar os empregados e seus
respectivos gerentes.

Figura 83 – SELF JOIN (ANSI SQL-92).

Fonte: SQLServerTutorial.NET (2019).

97
Para além disso, a Linguagem SQL também disponibiliza uma
cláusula para que seja possível fazer um produto cartesiano utilizando a
nova sintaxe. Essa cláusula é a CROSS JOIN e não exige a comparação
(cláusula ON) entre as colunas das tabelas relacionadas. No código abaixo,
o exemplo mostrado na Figura 80 foi reescrito usando a sintaxe ANSI SQL-
92 para fazer o produto cartesiano.

SELECT Production.ProductCategory.Name AS Nome_da_Categoria,


Production.ProductSubCategory.Name AS Nome_da_SubCategoria
FROM Production.ProductCategory
CROSS JOIN Production.ProductSubCategory
ORDER BY Nome_da_Categoria ASC, Nome_da_SubCategoria ASC;

Já no OUTER JOIN, é possível retornar as linhas que atendam ao


critério do join em ambas as tabelas (assim como acontece no INNER JOIN),
acrescentado de uma das opções abaixo:

 Linhas da tabela à esquerda, para as quais não foram encontradas


linhas correspondentes na tabela à direita  LEFT OUTER JOIN.

 Linhas da tabela à direita, para as quais não foram encontradas


linhas correspondentes na tabela à esquerda  RIGHT OUTER
JOIN.

 Linhas da tabela à esquerda, para as quais não foram encontradas


linhas correspondentes na tabela à direita, mais as linhas da tabela
à direita, para as quais não foram encontradas linhas
correspondentes na tabela à esquerda  FULL OUTER JOIN.

Em resumo, com um OUTER JOIN consegue-se exibir todas as linhas


de uma tabela juntamente com as linhas correspondentes entre as tabelas
na cláusula de join. Para as linhas que não tiverem correspondência na outra
tabela, a coluna retornada é representada com o valor NULL.

98
Figura 84 – LEFT OUTER JOIN (ANSI SQL-92).

Fonte: Concurso INEP/ENADE (2017).

No SQL Server, para se fazer uma operação de LEFT OUTER JOIN,


pode-se suprimir a cláusula OUTER, como mostrado na sintaxe abaixo.

SELECT *

FROM TABELA1 T1

LEFT JOIN TABELA2 T2

ON T1.id = T2.id_fk;

Para exemplificar o LEFT OUTER JOIN, foi escrita a query abaixo


para relacionar todos os produtos e seus valores nas vendas realizadas
(incluindo os produtos que não tiveram vendas ainda). Note que para os
produtos que não tiveram vendas ainda, a coluna Valor_na_Venda é
retornada com o valor NULL.

SELECT P.Name AS Nome_Produto, S.UnitPrice AS Valor_na_Venda

FROM Production.Product P

LEFT JOIN Sales.SalesOrderDetail S

ON P.ProductID = S.ProductID

ORDER BY Nome_Produto ASC;

É importante ressaltar que, ao contrário do que acontece no INNER


JOIN, para o LEFT JOIN e para o RIGHT JOIN a ordem em que as tabelas

99
são colocadas impacta diretamente no resultado retornado pela query. No
exemplo acima, invertendo-se a ordem no join, o resultado seria outro: todas
as vendas e seus respectivos produtos; ou seja, não retornaria produtos que
não tiveram vendas.

SELECT P.Name AS Nome_Produto, S.UnitPrice AS Valor_na_Venda


FROM Sales.SalesOrderDetail S
LEFT JOIN Production.Product P
ON P.ProductID = S.ProductID
ORDER BY Nome_Produto ASC;

Com base nessa ordem, podemos concluir que o RIGHT JOIN tem o
efeito contrário do LEFT JOIN, como mostrado na operação de conjunto
abaixo.

Figura 85 – RIGHT OUTER JOIN (ANSI SQL-92).

Fonte: Gustavo (2019).

Para exemplificar o RIGHT OUTER JOIN, vamos considerar a ordem


das tabelas no exemplo acima, com a tabela Product à direita, para trazer
todos os produtos e seus valores de vendas, incluindo os produtos que ainda
não tiveram vendas. Perceba que é possível obter o mesmo valor do exemplo
da página anterior alterando a ordem das tabelas e o sentido do join.

100
Figura 86 – RIGTH OUTER JOIN (ANSI SQL-92).

Fonte: Gustavo (2019).

Importante mencionar que, assim como no INNER JOIN, é possível


realizar SELF JOIN usando LEFT ou RIGHT JOIN. Dessa forma, no exemplo
da Figura 82, se quiséssemos retornar também os funcionários que não têm
gerente, ou seja, os gestores (coluna manager = NULL), a query ficaria como
mostrado na figura a seguir.

Figura 87 – SELF LEFT JOIN (ANSI SQL-92).

Fonte: SQLServerTutorial.NET (2019).

O último tipo de JOIN, o FULL JOIN, permite recuperar todas as


linhas das tabelas envolvidas mesmo que não haja correspondência na
cláusula da operação do join, como mostrado na operação de conjunto
representada na figura abaixo:

101
Figura 88 – FULL OUTER JOIN (ANSI SQL-92).

Fonte: Gustavo (2019).

Para além disso, pode-se utilizar a cláusula WHERE em conjunto com


a cláusula JOIN, de forma a executar as seguintes operações de conjuntos:

Figura 89 – Outras operações de conjunto.

Fonte: Gustavo (2019).

102
7
Capítulo 7. Subconsultas
Uma subconsulta é uma instrução SELECT aninhada em outra
consulta, ou seja, em outra instrução SELECT. A consulta aninhada, que é a
subconsulta, é chamada de consulta interna (inner query). A consulta que
contém a subconsulta é chamada de consulta externa (outer query).

O objetivo de uma subconsulta é retornar resultados para a consulta


externa, de forma a permitir a construção de queries mais complexas, sendo
um recurso amplamente usado em projetos de bancos de dados.

A forma dos resultados retornados pela subconsulta determinará se


ela é uma subconsulta escalar ou uma subconsulta multivalorada. Uma
subconsulta escalar, da mesma forma que uma função escalar, retorna um
único valor. Já uma subconsulta multivalorada retorna valores múltiplos
como se fosse uma tabela com uma coluna apenas. Além disso, a Linguagem
SQL permite escrever subconsultas que estão correlacionadas com a
consulta externa, referenciando uma ou mais colunas da consulta externa.

Nos capítulos a seguir, veremos cada tipo de subconsulta existente,


sua aplicabilidade e exemplos.

7.1. Subconsulta escalar e multivalorada


Uma subconsulta escalar é uma instrução SELECT aninhada
internamente a uma consulta externa, escrita de forma a retornar um único
valor. Esse tipo de subconsulta pode ser usado em qualquer lugar de uma
instrução SQL externa, em que uma expressão de valor único é permitida,
como em uma instrução SELECT, WHERE, HAVING ou até mesmo em uma
cláusula FROM.

Para escrever uma subconsulta escalar, devem ser observadas as


seguintes regras que podem variar de acordo com o SGBD em questão:

104
 A subconsulta deve ser colocada entre parênteses.

 Podem existir vários níveis de subconsultas. Por exemplo, se


tivermos uma consulta de 3 níveis, temos 1 consulta interna dentro
de uma subconsulta externa, que, por sua vez, está dentro de uma
consulta externa. No SQL Server, há suporte para até 32 níveis de
consultas.

 Se a subconsulta retornar um conjunto vazio, o resultado da


subconsulta será convertido e retornado como um NULL.

Uma dica muito útil para se construir subconsultas é escrever


primeiramente a consulta mais interna, de forma a ir aumentando a
complexidade da query gradativamente. Suponha que no nosso banco de
exemplo deseja-se retornar os itens inclusos na última venda realizada.
Primeiramente, para retornar a última venda realizada, a query ficaria algo
como mostrado abaixo. Perceba que se trata de uma query que retornará
apenas um valor (última ordem de venda), se tratando de uma query escalar:

SELECT MAX(SalesOrderID) AS Última_Venda

FROM Sales.SalesOrderHeader;

De posse dessa subconsulta, já podemos pensar em inseri-la na


consulta externa, ficando algo como mostrado abaixo:

SELECT SalesOrderID, SalesOrderDetailID, OrderQty, ProductID, LineTotal

FROM Sales.SalesOrderDetail

WHERE SalesOrderID = ( SELECT MAX(SalesOrderID) AS Última_Venda

FROM Sales.SalesOrderHeader

105
Importante destacar que, precedendo a subconsulta escalar, devem
ser usados operadores de comparação que exigem a comparação com um
valor único. Esses operadores são: =, !=, <, <=, > e >=. Caso a consulta mais
interna retorne mais de um valor, será exibido o erro como mostrado na
figura abaixo, informando que não é permitido esse tipo de comparação.

Figura 90 – Erro em Subconsulta Escalar.

Fonte: Gustavo (2019).

Além do uso na cláusula WHERE, é permitido também usar


subconsulta escalar na cláusula HAVING, como mostrado no exemplo
abaixo, onde deseja-se listar as vendas diárias do ano de 2013 com valores
inferiores à média de vendas do ano anterior:

SELECT OrderDate AS Data_da_Venda,

SUM(TotalDue) AS Valor_Total_Diário_de_Vendas

FROM Sales.SalesOrderHeader

WHERE YEAR(OrderDate)='2013'

GROUP BY OrderDate

HAVING SUM(TotalDue) < (

SELECT AVG(TotalDue)

106
FROM Sales.SalesOrderHeader

WHERE YEAR(OrderDate)='2012'

ORDER BY 1 ASC;

Percebam também que no exemplo anterior, podemos encontrar um


tipo de subconsulta muito útil, chamado subconsulta recursiva. Com esse
tipo de subconsulta, é permitido, em uma mesma query, executar um
SELECT em uma tabela e uma subconsulta nessa mesma tabela.

Para as situações em que deseja-se que a subconsulta retorne mais


de um valor, a Linguagem SQL fornece o tipo de consulta multivalorada.
Esse tipo de subconsulta pode ser usado, então, onde as subconsultas
escalares não forem aplicáveis. Da mesma forma que na subconsulta escalar,
a subquery (subconsulta) deve ser colocada entre parênteses e podem
existir vários níveis de subconsultas, que são as chamadas subconsultas
aninhadas.

Os operadores que podem ser usados com uma subconsulta


multivalorada são o IN e o EXISTS, e a mesma dica para a construção de
queries com subconsulta escalar aplica-se também à construção de queries
com subconsulta multivalorada: escrever primeiramente a consulta mais
interna, de forma a ir aumentando a complexidade da query gradativamente.

O operador IN verifica se a coluna ou expressão informada na


cláusula WHERE possui valores que correspondam aos valores retornados
pela subconsulta multivalorada. Para exemplificarmos esse operador,
suponha que se deseja retornar a identificação e o número da conta dos
clientes da Austrália e França. A query ficaria algo como:

SELECT CustomerID, AccountNumber

107
FROM Sales.Customer

WHERE TerritoryID IN (

SELECT TerritoryID

FROM Sales.SalesTerritory

WHERE Name ='Australia' OR Name = 'France'

);

Percebam que nas situações em que houver uma relação entre as


tabelas envolvidas em uma subconsulta multivalorada, como no exemplo
anterior, a query pode ser reescrita de forma a utilizar join, sendo mais
performática, como mostrado no exemplo a seguir:

SELECT C.CustomerID, C.AccountNumber

FROM Sales.Customer C

JOIN Sales.SalesTerritory T

ON C.TerritoryID = T.TerritoryID

WHERE T.Name ='Australia' OR T.Name = 'France'

Um operador que pode ser usado junto ao operador IN, mas que por
questões de performance deve ser evitado, é o operador NOT. Com ele, pode-
se inverter o resultado esperado da comparação feita com o operador IN,
que, na prática, pode-se traduzir para “não está contido”. Assim sendo, com
NOT IN, a verificação feita é a de que a coluna ou expressão informada na
cláusula WHERE possua valores que não correspondam a nenhum dos
valores retornados pela subconsulta multivalorada, o que exige a leitura da
tabela inteira. Para exemplificar, suponha que agora se deseja retornar a
identificação e o número da conta de todos os clientes, exceto os da
Austrália e da França. A query ficaria algo como:

SELECT CustomerID, AccountNumber

108
FROM Sales.Customer

WHERE TerritoryID NOT IN (

SELECT TerritoryID

FROM Sales.SalesTerritory

WHERE Name ='Australia' OR Name = 'France'

);

Assim como nas subconsultas escalares, além do uso na cláusula


WHERE, é permitido também usar subconsultas multivaloradas na cláusula
HAVING, seja com o operador IN, seja com os operadores NOT IN.

A título de exemplo, na query abaixo deseja-se listar o valor total das


vendas dos dias no ano de 2013, que no ano anterior foram os 5 dias com
maior valor de vendas.

SELECT OrderDate AS Data_da_Venda,

SUM(TotalDue) AS Valor_Total_Diário_de_Vendas

FROM Sales.SalesOrderHeader

WHERE YEAR(OrderDate)='2013'

GROUP BY OrderDate

HAVING CAST (DAY(OrderDate) AS VARCHAR(2)) + '-' +

CAST(MONTH(OrderDate) AS VARCHAR(2))

IN (

SELECT TOP (5) CAST (DAY(OrderDate) AS VARCHAR(2)) + '-' +

CAST(MONTH(OrderDate) AS VARCHAR(2))

FROM Sales.SalesOrderHeader

WHERE YEAR(OrderDate)='2012'

109
GROUP BY OrderDate

ORDER BY SUM(TotalDue)

ORDER BY 1 ASC;

7.2. Subconsultas correlacionadas e com operadores de conjuntos


Nos exemplos de subconsultas mostrados anteriormente, sejam
elas escalar ou multivalorada, podemos perceber que as subconsultas não
possuem nenhuma dependência com a consulta externa e podem ser
executadas isoladamente. Esse tipo de subconsulta é denominada
subconsulta independente.

Já as subconsultas correlacionadas, que podem ser escritas como


escalares ou multivaloradas, não podem ser executadas separadamente da
consulta externa. Isso ocorre devido ao fato de a consulta externa passar
um valor para a consulta interna (subconsulta), para ser usado como um
parâmetro na execução dela.

Outra peculiaridade é que, diferentemente das subconsultas


independentes processadas uma vez, as subconsultas correlacionadas
executam várias vezes, de forma que a consulta externa é executada
primeiro e, para cada linha retornada, a consulta interna é processada.

Para clarificar, o exemplo a seguir usa uma subconsulta


correlacionada para retornar as vendas mais recentes feitas por cada
empregado. A subconsulta aceita um valor de entrada da consulta externa,
usa a entrada em sua cláusula WHERE, e retorna um resultado escalar para
a consulta externa.

SELECT Q1.SalesOrderID, Q1.SalesPersonID, Q1.OrderDate

FROM Sales.SalesOrderHeader AS Q1

WHERE Q1.OrderDate = (

110
SELECT MAX(Q2.OrderDate)

FROM Sales.SalesOrderHeader AS Q2

WHERE Q2.SalesPersonID = Q1.SalesPersonID

ORDER BY Q1.SalesPersonID, Q1.OrderDate;

Utilizando-se do recurso de subconsulta correlacionada, é possível


escrever queries bem mais performáticas do que as escritas usando o
operador IN. Para isso, usamos o operador EXISTS em conjunto com a
subconsulta correlacionada. Esse operador, ao contrário do operador IN,
interrompe a execução da subconsulta, assim que uma correspondência for
encontrada. Com isso, estamos falando que o operador EXISTS, ao invés de
recuperar um valor escalar ou uma lista com vários valores em uma
subconsulta, ele simplesmente verifica se existe qualquer linha, no
resultado, que satisfaça a condição de comparação com a consulta mais
externa.

No exemplo a seguir, deseja-se retornar o ID e o bônus das pessoas


que fizeram pelo menos uma venda no ano de 2011.

SELECT P.BusinessEntityID, P.Bonus

FROM Sales.SalesPerson P

WHERE EXISTS (

SELECT *

FROM Sales.SalesOrderHeader V

WHERE V.SalesPersonID = P.BusinessEntityID

AND YEAR(OrderDate) = '2011'

ORDER BY 1 ASC;

111
Conceitualmente falando, o operador EXISTS é equivalente a
recuperar os resultados contando as linhas retornadas e comparando se
essa contagem é maior que zero.

SELECT P.BusinessEntityID, P.Bonus

FROM Sales.SalesPerson P

WHERE (

SELECT COUNT(*)

FROM Sales.SalesOrderHeader V

WHERE V.SalesPersonID = P.BusinessEntityID

AND YEAR(OrderDate) = '2011'

)>0

ORDER BY 1 ASC;

Da mesma forma que o operador IN, o operador EXISTS pode ser


usado com o operador NOT. Dessa forma, usando-se NOT EXISTS,
consegue-se retornar os resultados para os quais não foram encontradas
correspondências na subconsulta correlacionada.

Aproveitando o penúltimo exemplo, se desejássemos retornar as


pessoas que não fizeram vendas no ano de 2011, bastaria adicionar o
operador NOT, como mostrado a seguir.

SELECT P.BusinessEntityID, P.Bonus

FROM Sales.SalesPerson P

WHERE NOT EXISTS (

SELECT *

FROM Sales.SalesOrderHeader V

WHERE V.SalesPersonID = P.BusinessEntityID

112
AND YEAR(OrderDate) = '2011'

ORDER BY 1 ASC;

Da mesma forma, conceitualmente falando, os operadores NOT


EXISTS são equivalentes a recuperar os resultados contando as linhas
retornadas e comparando essa contagem com zero.

SELECT P.BusinessEntityID, P.Bonus

FROM Sales.SalesPerson P

WHERE (

SELECT COUNT(*)

FROM Sales.SalesOrderHeader V

WHERE V.SalesPersonID = P.BusinessEntityID

AND YEAR(OrderDate) = '2011'

)=0

ORDER BY 1 ASC;

Além dos tipos de subconsultas vistos anteriormente, onde temos


uma consulta externa e a consulta interna (subconsulta), a Linguagem SQL
possui operadores de conjuntos para realizar operações entre duas ou mais
subconsultas independentes entre si. Nesse tipo de subconsulta, ao
contrário das subconsultas vistas anteriormente, onde a consulta externa
não é independente (apenas a consulta interna), todas as subconsultas são
independentes e podem ser executadas separadamente.

Para realizar as operações de conjunto UNIÃO, INTERSEÇÃO e


DIFERENÇA, a linguagem T-SQL disponibiliza os operadores de conjunto
UNION, INTERSECT e EXCEPT, respectivamente. Esses operadores, apesar
de cada um se prestar a um propósito, possuem algumas características em
comum:

113
 Cada conjunto de entrada é o resultado de uma consulta
(subconsulta), que pode incluir qualquer instrução SELECT, mas não
pode possuir uma cláusula ORDER BY. Caso seja necessário
ordenar o resultado, o ORDER BY deve ser colocado na consulta geral
(query completa com todos as subconsultas e os respectivos
operadores de conjuntos).

 Os conjuntos de entrada devem ter o mesmo número de colunas e


as colunas devem ter tipos de dados compatíveis. Se não forem
inicialmente compatíveis, devem ser compatíveis através da
conversão implícita (caso os tipos de dados a suportem de acordo
com as regras de precedência de tipos de dados vistas na página 67)
ou da conversão explícita usando CAST ou CONVERT.

 Um valor nulo (NULL) em um conjunto é tratado como igual a outro


valor nulo em outro conjunto.

Isso posto, vamos inicialmente ver a operação de união entre duas


ou mais subconsultas que pode ter duas vertentes:

 Usando o operador UNION ALL: não elimina as linhas duplicadas.

Figura 91 – Operação com UNION ALL.

Fonte: https://sqlitetutorial.net/ (2019).

A sintaxe para usar essa vertente é: SELECT1

UNION ALL

SELECT2

114
UNION ALL

SELECT[n]

[ORDER BY]

No exemplo a seguir, deseja-se retornar todas as linhas, de forma


que seja possível identificar aqueles médicos que também são pacientes do
hospital e vice-versa:

SELECT nome, cpf, telefone

FROM Tab_Medicos

UNION ALL

SELECT nome, cpf, telefone

FROM Tab_Pacientes;

 Usando o operador UNION: exclui as linhas duplicadas.

Figura 92 – Operação com UNION.

Fonte: sqlitetutorial.net (2019).

A sintaxe para usar essa vertente é: SELECT1

UNION

SELECT2

UNION

SELECT[n]

115
[ORDER BY]

Usando o mesmo exemplo anterior, mas supondo que agora


quiséssemos apenas retornar a lista com nomes distintos das pessoas que
estão cadastradas na base de dados do hospital, independentemente se é
médico ou paciente, a query precisaria de usar o operador UNION para
eliminar as linhas duplicadas.

SELECT nome, cpf, telefone

FROM Tab_Medicos

UNION

SELECT nome, cpf, telefone

FROM Tab_Pacientes;

Para realizar a operação de interseção, onde deseja-se encontrar os


valores comuns a dois ou mais conjuntos, usa-se o operador INTERSECT da
Linguagem T-SQL. Esse operador retornará apenas as linhas distintas que
existirem em ambos os conjuntos, ou seja, linhas repetidas são eliminadas
por padrão.

Figura 93 – Operação com INTERSECT.

Fonte: sqlitetutorial.net (2019).

A sintaxe é: SELECT1

INTERSECT

SELECT2

116
INTERSECT

SELECT[n]

[ORDER BY]

Usando o mesmo exemplo anterior, mas supondo que agora


quiséssemos retornar a lista com nomes distintos das pessoas que são
médicos e pacientes, a query precisaria de usar o operador INTERSECT.

SELECT nome, cpf, telefone

FROM Tab_Medicos

INTERSECT

SELECT nome, cpf, telefone

FROM Tab_Pacientes;

Por fim, para realizar a operação de exceção (diferença), onde


deseja-se retornar as linhas distintas da subconsulta de entrada à esquerda
(ou acima na query) que não são retornadas pela subconsulta de entrada à
direita (ou abaixo na query), usa-se o operador EXCEPT da Linguagem T-
SQL.

Figura 94 – Operação com EXCEPT.

Fonte: sqlitetutorial.net (2019).

A sintaxe é: SELECT1

EXCEPT

117
SELECT2

EXCEPT

SELECT[n]

[ORDER BY]

Usando o mesmo exemplo anterior, mas supondo que agora


quiséssemos retornar a lista com nomes distintos das pessoas que são
médicos e não são pacientes, a query precisaria de usar o operador EXCEPT.

SELECT nome, cpf, telefone

FROM Tab_Medicos

EXCEPT

SELECT nome, cpf, telefone

FROM Tab_Pacientes;

Importante observar que como se trata de uma operação de


subtração, a ordem dos conjuntos na operação irá afetar diretamente o
resultado. Dessa forma, no exemplo anterior, se quiséssemos retornar a lista
com nomes distintos das pessoas que são pacientes e não são médicos, a
ordem das subconsultas precisaria ser invertida:

SELECT nome, cpf, telefone

FROM Tab_Pacientes

EXCEPT

SELECT nome, cpf, telefone

FROM Tab_Medicos;

118
8
Capítulo 8. Inserção, Atualização e Exclusão de Dados
Ainda dentro da classe DML da Linguagem SQL, encontram-se os
comandos para realizar a inserção, a atualização e a exclusão de dados, que
serão vistos com mais detalhes nos capítulos a seguir.

8.1. Inserindo Dados


Para inserir uma ou mais linhas em uma tabela ou visão (será vista
no capítulo 8), ação essa também referida como persistir dados, é usado o
comando INSERT. Apesar de existirem outras formas de inserir dados em
uma tabela, como usando os comandos de carga massiva de dados
(operações de bulkload), o comando INSERT é o mais usado.

Sua sintaxe mais simples é mostrada abaixo, sendo que a lista de


colunas é opcional, mas, ao informá-las, o código fica mais autoexplicativo e
seguro, diminuindo o risco de inserção de valores de uma coluna em outra,
e sendo possível também definir a ordem de inserção dos valores das
colunas na tabela. Ao não informar a lista de colunas, é preciso inserir os
valores para as colunas na ordem em que elas estão criadas na tabela.

INSERT [INTO] <Tabela ou visão> [lista_de_colunas]

VALUES (Valor | Expressão | NULL | DEFAULT)

Supondo que exista uma tabela de nome TAB1, com as colunas COL1
e COL2, ambas do tipo de dados numérico, o comando para inserir uma linha
nessa tabela ficaria algo como:

INSERT INTO TAB1 (COL1, COL2)

VALUES (100, 500);

120
Omitindo a lista de colunas, ficaria como mostrado abaixo, indicando
que o valor 100 seria inserido na primeira coluna da tabela TAB1 e o valor
500 na segunda coluna.

INSERT INTO TAB1

VALUES (100, 500);

Supondo agora que COL2 fosse do tipo de dados string, o valor ou


expressão a ser inserida precisa ser colocada entre aspas simples (‘ ’), como
demonstrado abaixo:

INSERT INTO TAB1 (COL1, COL2)

VALUES (100, ‘Valor não numérico’);

Para as situações em que a coluna aceita valores nulos e deseja-se


omitir o valor a ser inserido, deve-se especificar NULL na lista de valores a
serem inseridos:

INSERT INTO TAB1 (COL1, COL2)

VALUES (100, NULL);

Nos casos em que a coluna foi criada com um valor default e deseja-
se inserir esse valor, deve-se especificar DEFAULT na lista de valores a
serem inseridos, como mostrado no exemplo abaixo:

Figura 95 – INSERT com DEFAULT.

Fonte: Gustavo (2019).

121
Usando apenas um comando INSERT, é possível inserir mais de uma
linha de uma só vez, basta separar as várias cláusulas VALUES com vírgula.
No nosso exemplo anterior, se desejássemos inserir 3 linhas, o comando
ficaria como:

INSERT INTO TAB1 (COL1, COL2)

VALUES (100, ‘Valor não numérico’) ,

(200, ‘Valor não numérico 2’) ,

(300, ‘Valor não numérico 3’);

Uma possibilidade muito interessante do comando INSERT é


utilizar uma consulta SELECT em outra tabela ou conjunto de tabelas para
retornar os valores a serem inseridos na tabela em questão. No nosso
exemplo, supondo que tivéssemos também a tabela TAB2 com as colunas
COL3 (numérica), COL4 (numérica) e COL5 (string), e desejássemos inserir
na TAB1 todos os valores da COL4 e COL5 da tabela TAB2, o comando ficaria
como mostrado abaixo.

INSERT INTO TAB1 (COL1, COL2)

SELECT COL4, COL5 FROM TAB2;

Na mesma linha de se usar uma consulta SELECT para inserir dados


em uma tabela, pode-se também executar uma procedure (será vista com
mais detalhes no capítulo 8), como mostrado no exemplo abaixo.

INSERT INTO TAB1 (COL1, COL2)

EXEC PROC1;

Outra possibilidade de inserir dados em uma tabela é usando a


cláusula SELECT INTO. Essa cláusula é similar à INSERT INTO SELECT, com
a exceção de que a tabela destino dos dados não pode estar criada, visto que
a cláusula SELECT INTO criará a tabela em tempo de execução.

122
Essa nova tabela é criada com a estrutura física definida pela lista de
colunas na cláusula SELECT. Cada coluna na nova tabela terá o mesmo
nome, tipo de dados e anulabilidade da coluna correspondente (ou
expressão) da lista de colunas na cláusula SELECT. Entretanto, índices e
constraints não são criados na nova tabela. A sintaxe para essa opção é
mostrada abaixo.

SELECT coluna1, coluna2, …

INTO Nova_Tabela FROM Tabela_Origem;

Figura 96 – SELECT INTO.

Fonte: Gustavo (2019).

8.2. Atualizando Dados


Para alterar dados existentes em uma tabela ou visão, a Linguagem
SQL fornece a instrução UPDATE. Essa instrução opera em um conjunto de
linhas definido por uma condição em uma cláusula WHERE ou join, que
possui a mesma estrutura que uma cláusula WHERE em uma instrução
SELECT e pode-se valer dos mesmos recursos. Para atribuir o novo valor à
coluna, é usada a cláusula SET, que permite também a atualização dos
valores de uma ou mais colunas, separadas por vírgulas.

123
Dessa forma, a sintaxe da instrução UPDATE, em linhas gerais, é:

UPDATE <Nome_Tabela>

SET <Coluna1> = { valor | expressão | DEFAULT | NULL },

<Coluna2> = { valor | expressão | DEFAULT | NULL },

<ColunaN> {…n}

WHERE <Condição>;

Considerando os valores da tabela TAB2 do exemplo mostrado na


figura 96, se quiséssemos atualizar os valores da coluna COL3 para 500, de
todas as linhas onde o valor da coluna COL1 fossem iguais a 10, o comando
SQL ficaria algo como:

UPDATE TAB2

SET COL3 = 500

WHERE COL1 = 10;

Importante destacar que se não for especificada a cláusula WHERE,


a atualização será feita para todas as linhas da tabela. Dessa forma, omitindo
a cláusula WHERE no exemplo anterior, não mais atualizaríamos apenas as
linhas onde o valor da coluna COL1 fossem iguais a 10, e sim todas as linhas
da tabela.

UPDATE TAB2

SET COL3 = 500;

Como informado inicialmente, é perfeitamente possível atualizar


mais de uma coluna de uma vez, bastando separá-las por vírgula. Dessa
forma, se, no exemplo, quiséssemos atualizar os valores da coluna COL3

124
para 500 e da coluna COL1 para 600, de todas as linhas onde o valor da
coluna COL1 fosse igual a 10, o comando SQL ficaria algo como:

UPDATE TAB2

SET COL3 = 500, COL1 = 600

WHERE COL1 = 10;

8.3. Excluindo dados


Para excluir dados existentes em uma tabela ou visão, a Linguagem
SQL fornece a instrução DELETE. Essa instrução, assim como a cláusula
UPDATE, opera em um conjunto de linhas definido por uma condição em
uma cláusula WHERE ou join, que possui a mesma estrutura que uma
cláusula WHERE em uma instrução SELECT e pode-se valer dos mesmos
recursos. Sua sintaxe na forma mais simples é:

DELETE FROM <Nome_Tabela>

WHERE <Condição>;

Considerando os valores da tabela TAB2 do exemplo mostrado na


figura 96, se quiséssemos excluir as linhas onde o valor da coluna COL1
fossem iguais a 10, o comando SQL ficaria algo como:

DELETE FROM TAB2

WHERE COL1 = 10;

Importante destacar que se não for especificada a cláusula


WHERE, todas as linhas da tabela serão excluídas. Dessa forma, omitindo
a cláusula WHERE no exemplo anterior, não mais excluiríamos apenas as
linhas onde o valor da coluna COL1 fossem iguais a 10, e sim todas as linhas
da tabela.

DELETE FROM TAB2;

125
Para as situações em que se deseja excluir todos os dados de uma
tabela, por questões de performance, é preferível usar o comando
TRUNCATE da classe DDL da Linguagem SQL. Esse comando remove todas
as linhas de uma tabela sem registrar as exclusões de linhas
individualmente, consumindo menos recursos do servidor de banco de
dados e executando mais rápido que o DELETE sem a cláusula WHERE. Sua
sintaxe é TRUNCATE TABLE <Nome_da_Tabela>.

Assim como no comando UPDATE, é possível utilizar uma


subconsulta ou JOIN para retornar/obter os valores para as condições de
exclusão, como mostrado nos exemplos abaixo retirados da documentação
da Microsoft:

--Usando subconsulta

DELETE FROM Sales.SalesPersonQuotaHistory

WHERE BusinessEntityID IN (

SELECT BusinessEntityID

FROM Sales.SalesPerson

WHERE SalesYTD > 2500000

--Usando join

DELETE FROM Sales.SalesPersonQuotaHistory

FROM Sales.SalesPersonQuotaHistory AS spqh

INNER JOIN Sales.SalesPerson AS sp

126
ON spqh.BusinessEntityID = sp.BusinessEntityID

WHERE sp.SalesYTD > 2500000;

Para além disso, e contemplando as necessidades de certas


operações no banco de dados onde é preciso atualizar, inserir ou excluir
linhas de uma tabela, existe o comando MERGE. Com essa instrução é
possível inserir, atualizar e até excluir linhas de uma tabela, com base em
um join com um conjunto de dados de origem, tudo em uma única
instrução.

O comando MERGE atua nos dados de uma tabela destino, com base
em uma ou mais condições de decisão mostradas abaixo, acerca de qual
operação (INSERT/UPDATE/DELETE) será executada:

 Quando os dados de origem correspondem aos dados no destino,


ocorre a atualização dos dados.

 Quando os dados de origem não têm correspondência no destino,


ocorre a inserção desses dados.

 Quando os dados de destino não têm correspondência no conjunto


de dados de origem, ocorre a exclusão dos dados na tabela de
destino.

A sintaxe do comando MERGE na sua forma mais simples é:

MERGE

[ INTO ] <Tabela_Destino>

USING <Conjunto de Dados de Origem>

ON <Condição de Comparação para o Merge >

[WHEN MATCHED

127
THEN <Operação Quando Há Correspondência>]

[WHEN NOT MATCHED BY TARGET

THEN < Operação Quando Não Há Correspondência no Destino>]

[ WHEN NOT MATCHED BY SOURCE

THEN < Operação Quando Não Há Correspondência na Origem>]

Para exemplificar, na query abaixo deseja-se atualizar os campos


Data_Venda e Valor quando a venda já existir na tabela, e inserir a linha
(colunas Id_Venda, Origem.Data_Venda, Origem.Produto, Origem.Qtde e
Origem.Valor) quando a venda ainda não existir:

MERGE TAB_Venda_Destino AS Destino


USING TAB_Venda_Origem AS Origem ON (Origem.Id_Venda = Destino.Id_Venda)
WHEN MATCHED THEN -- Registro existe nas 2 tabelas
UPDATE SET
Destino.Data_Venda = Origem.Data_Venda,
Destino.Valor = Origem.Valor
WHEN NOT MATCHED THEN --Registro não existe no destino e deve ser inserido
INSERT
VALUES (Origem.Id_Venda, Origem.Data_Venda, Origem.Produto, Origem.Qtde,
Origem.Valor);

128
9
Capítulo 9. Linguagem de Controle de Transação (TCL)
9.1. Conceitos Básicos de Transação
As características que mais contribuíram para o respaldo, robustez e
integridade dos sistemas gerenciadores de bancos de dados relacionais
foram as suas propriedades ACID. Essas propriedades referem-se, em
grande parte, às transações que são executadas no SGBD, que nada mais
são do que uma sequência de instruções SQL.

Essas propriedades funcionam como regras para as transações


executadas em um SGBD relacional, tendo o seguinte significado:

 ATOMICIDADE: requer que as transações sejam “tudo ou nada” (“all


or nothing”), ou seja, se uma parte da transação falhar, a transação
inteira deve falhar e o estado do banco de dados permanece
inalterado. Em outras palavras, a transação será executada
totalmente ou não será executada, garantindo, assim, que as
transações sejam atômicas.

 CONSISTÊNCIA: garante que qualquer transação levará o banco de


dados de um estado válido a outro. Em caso de sucesso, a transação
cria um novo estado válido dos dados ou, em caso de falha, retorna
todos os dados ao estado imediatamente anterior ao início da
transação.

 ISOLAMENTO: garante que execuções concorrentes (em paralelo)


de transações resultem em um estado do banco de dados que seria
obtido caso as transações fossem executadas serialmente. Isso
ocasiona que uma transação em andamento, mas ainda não
validada, permanece isolada de qualquer outra operação,

130
garantindo que a transação não sofra interferência de nenhuma
outra transação concorrente.

 DURABILIDADE: garante que, uma vez que uma transação tenha


sido confirmada, ela permanecerá assim, mesmo no caso de um
reinício do sistema, crash, falta de energia ou erros posteriores.

Figura 97 – Propriedades ACID.

Fonte: Gustavo (2019).

Dois termos muito falados quando o assunto é transação são o


COMMIT e o ROLLBACK. Mencionamos commit quando queremos dizer que
a transação foi validada, confirmada, persistida. Já o rollback é mencionado
nas situações em que a transação não foi confirmada/persistida e precisou
ser desfeita.

Em termos de criação, as transações podem ocorrer de duas formas:

 EXPLICITAMENTE: iniciadas através de comandos da Linguagem


de Controle de Transação (Transaction Control Language – TCL),
uma classe da Linguagem SQL para controlar transações.

131
 IMPLICITAMENTE: também chamadas de transações com
autocommit. As instruções enviadas separadamente para execução
são automaticamente inseridas em uma transação pelo SGBD.
Essas transações são confirmadas (“commitadas”)
automaticamente quando a instrução é bem-sucedida, ou revertidas
automaticamente quando a instrução encontra um erro em tempo
de execução. É como se o SGBD abrisse a transação explicitamente
e acompanhasse o status dela para saber se a confirma no banco de
dados ou se a desfaz, tudo isso de forma transparente para o usuário.

Muitos SGBDs, como o SQL Server, permitem os dois modos, mas


alguns, como o Oracle, só permitem o modo explícito, sendo fundamental
para quem construirá aplicações com a linguagem SQL, conhecer o commit
mode do SGBD com o qual irá trabalhar.

9.2. Controle de Transações


As transações explícitas são controladas
(criadas/confirmadas/desfeitas) usando os comandos da classe TCL, sendo
que cada SGBD pode implementar variações ou novos comandos para o
propósito de trabalho com transação.

Para iniciar uma transação, é usado o comando BEGIN


TRANSACTION. Depois de iniciada uma transação, ela deve ser finalizada
adequadamente, usando COMMIT em caso de sucesso e se desejar persistir
a transação, ou ROLLBACK em caso de falha ou desistência de persistência
da transação.

 Iniciando e confirmando uma transação:

BEGIN TRANSACTION;

DELETE FROM HumanResources.JobCandidate

WHERE JobCandidateID = 13;

132
COMMIT;

 Iniciando e desfazendo uma transação:

BEGIN TRANSACTION;

INSERT INTO ValueTable VALUES(1);

INSERT INTO ValueTable VALUES(2);

ROLLBACK;

Importante ressaltar que, dada a propriedade ACID isolamento,


objetos envolvidos em uma transação de uma sessão de usuário não estão
disponíveis para outras sessões enquanto a transação não for finalizada.
Dessa forma, ao trabalhar com transações explícitas, é muito importante
ficar atento para não deixar transações abertas no banco de dados sem nada
em execução, simples e puramente por falta do devido tratamento
(commit/rollback) a uma transação aberta, pois isso pode causar uma fila
enorme de espera devido aos “bloqueios” nos objetos.

Uma possibilidade ao se trabalhar com transações é utilizá-las de


forma aninhada em N níveis, como o exemplo mostrado abaixo:

BEGIN TRANSACTION;

UPDATE table1 ...;

BEGIN TRANSACTION;

UPDATE table2 ...;

SELECT * from table1;

COMMIT;

UPDATE table3 ...;

COMMIT;

133
Para além disso, um recurso disponível na maioria dos SGBDs é o de
nomear transações e usar esses nomes para “commitá-las” a qualquer
momento:

BEGIN TRANSACTION T1;

UPDATE table1 ...;

BEGIN TRANSACTION T2;

UPDATE table2 ...;

SELECT * from table1;

COMMIT TRANSACTION T2;

UPDATE table3 ...;

COMMIT TRANSACTION T1;

134
10
Capítulo 10. Linguagem de Controle de Acesso a Dados (DCL)
10.1. Segurança em Bancos de Dados
Uma preocupação constante, principalmente na era da informação
que nos encontramos, é em relação à proteção dos dados armazenados. Na
camada de banco de dados, essa proteção deve ser feita externamente ao
SGBD (proteção do servidor, firewall, segmentação de rede, mecanismos
para evitar invasões e ataques de negação de serviço etc.), bem como
internamente.

Dentro do SGBD, a proteção aos objetos e dados, em termos de


permissão de acesso ou permissão para executar uma ação (comando), é
configurada através da Linguagem de Controle de Acesso a Dados (Data
Control Language - DCL), uma classe da Linguagem SQL também. Dentro
dessa linguagem, os comandos mais conhecidos e utilizados são:

 GRANT: comando DCL usado para conceder permissões em objetos


ou permissões para executar algum comando.

 REVOKE: comando DCL usado para remover permissões em objetos


ou permissões para executar algum comando.

Em relação aos objetos que podem ser protegidos, os mecanismos e


a granularidade de proteção, cada SGBD disponibiliza sua gama de recursos
e comandos para habilitar, configurar e gerenciar seu framework de
segurança. A título de exemplo, o SQL Server fornece os componentes
abaixo para controlar quais usuários podem fazer log-on no SQL Server,
quais dados eles podem acessar e quais operações eles podem executar:

 PERMISSION (Privilégio): permissão para executar alguma ação, ou


seja, executar algum comando SQL.

136
 ROLE (Papel): conjunto de privilégios que pode ser concedido a
usuários ou a outras roles. São criadas com o comando CREATE
ROLE da classe DDL da Linguagem SQL.

 PRINCIPALS (Entidades): usuários, grupos ou processos com


acesso concedido a uma instância do SQL Server, no nível do
servidor ou do banco de dados. As entidades no nível do servidor
incluem logins e roles de servidor (server roles). As entidades no
nível do banco de dados incluem usuários e roles de banco de dados
(database roles). Também são criados usando-se o comando
CREATE da classe DDL.

 Exemplo de comando para criar uma PRINCIPAL do tipo login:

CREATE LOGIN UsrIGTI

WITH PASSWORD = 'Pa55w.rd',

DEFAULT_DATABASE = [BDIGTI];

 SECURABLES: objetos, no nível do servidor ou do banco de dados,


nos quais são concedidas as permissões para os principals.

Figura 98 – Principals, Permissions e Securables.

Fonte: Microsoft (2008).

137
Figura 99 – Principals e Securables.

Fonte: Microsoft (2008).

10.2. Concessão e revogação de privilégios


As permissões em bancos de dados relacionais são gerenciadas
usando-se as instruções GRANT e REVOKE da classe DCL da Linguagem
SQL. As permissões que se aplicam a tabelas ou a views, para acessar ou
manipular dados, são SELECT, INSERT, UPDATE e DELETE.

No exemplo abaixo, está sendo concedida a permissão de SELECT na


tabela Address do schema (owner) Person, para o usuário
UsrAdventureSystem.

GRANT SELECT ON [Person].[Address] TO UsrAdventureSystem;

Já no exemplo abaixo, estão sendo concedidas as permissões de


SELECT, INSERT, DELETE e UPDATE na tabela Product do schema (owner)
Production, para o usuário UsrAdventureSystem.

138
GRANT SELECT, INSERT, DELETE, UPDATE ON [Production].[Product] TO
UsrAdventureSystem;

Uma opção bem útil na instrução GRANT é permitir que o usuário


que recebeu uma permissão possa concedê-la para outro usuário. Essa
possibilidade é feita com a cláusula WITH GRANT OPTION. No exemplo
abaixo, está sendo concedida a permissão de DELETE na tabela
DatabaseLog para o usuário UsrAdventureSystem, permitindo que ele possa
conceder essa permissão para outro usuário.

GRANT DELETE ON DatabaseLog

TO UsrAdventureSystem WITH GRANT OPTION;

Da mesma forma que as permissões para permitir a execução de


comandos DML, estão disponíveis as permissões para permitir a execução
de comandos DDL. No exemplo abaixo, está sendo concedida a permissão de
criar uma tabela para o usuário UsrAdventureSystem.

GRANT CREATE TABLE TO UsrAdventureSystem;

Por outro lado, para se remover uma permissão, usa-se a cláusula


REVOKE, cuja sintaxe pode ser observada no exemplo abaixo, onde está
sendo removida a permissão de DELETE na tabela DatabaseLog, do usuário
UsrAdventureSystem.

REVOKE DELETE ON DatabaseLog FROM UsrAdventureSystem;

Muitas outras permissões e opções de segurança podem ser


configuradas no SGBD, mas para efeitos do padrão ISO da Linguagem SQL,
as instruções GRANT e REVOKE são suficientes para entender a
funcionalidade da classe DCL.

139
11
Capítulo 11. Programação com a Linguagem T-SQL
11.1. Visões (Views) e CTEs
Uma view, em linhas gerais, é uma query armazenada, criada como
um objeto no banco de dados. Ao contrário das tabelas, uma view não
armazena dados e são vistas como tabelas virtuais dinâmicas para exibir
dados específicos de uma ou mais tabelas/views. Em outras palavras, a view
é definida por uma query no momento da sua criação, que especifica
exatamente os dados que essa view irá retornar.

Views são criadas com o comando CREATE VIEW da classe DDL da


Linguagem SQL, podendo ser alteradas pelo comando ALTER VIEW e
excluídas através do comando DROP VIEW.

As vantagens de se usar views são:

 Simplificam os relacionamentos complexos entre tabelas,


mostrando apenas os dados relevantes e ajudando os usuários a se
concentrarem no(s) subconjunto(s) de dados relevante(s) para eles,
ou com os quais eles têm permissão para trabalhar. Dessa forma, os
usuários não precisam ver as consultas complexas que estão por trás
da criação da view, trabalhando de forma transparente como se
fosse uma única tabela.

 Fornecem segurança, permitindo que os usuários vejam apenas o


que eles estão autorizados a ver. Views podem ser utilizadas para
limitar o acesso a determinados conjuntos de dados. Incluindo na
query de criação da view, apenas os dados que os usuários estão
autorizados a ver; os dados privados são mantidos em sigilo. As
visualizações são amplamente usadas também como um
mecanismo de segurança, fornecendo aos usuários acesso aos

141
dados através da view, mas não concedendo permissões
diretamente às tabelas base da view.

 Fornece uma camada de abstração, além de compatibilidade com


versões anteriores do schema físico, caso as tabelas base mudem.

 Evita problemas de performance causado por filtros indevidos ou


ausentes nas queries que consultam diretamente as tabelas base
da view;

 No caso de views indexadas, oferecem ganhos significativos de


performance.

A título de exemplo, no código abaixo está sendo criada uma view de


nome VW_Clientes_Australia para retornar o ID e o Número da Conta dos
clientes que são da Austrália:

CREATE VIEW VW_Clientes_Australia AS

SELECT CustomerID, AccountNumber

FROM Sales.Customer

WHERE TerritoryID IN (

SELECT TerritoryID

FROM Sales.SalesTerritory

WHERE Name ='Australia'

);

Após criada a view, pode-se utilizá-la como se fosse uma tabela,


inclusive participando de joins, agrupamentos e novos filtros.

SELECT *

FROM VW_Clientes_Australia

142
WHERE CustomerID BETWEEN 1 AND 100;

Uma observação importante é que a query de criação da view não


pode contar a cláusula ORDER BY. Dessa forma, quando desejar ordenar os
dados da view, deve-se usar a cláusula ORDER BY na query que utilizará a
view para retornar os dados, como mostrado abaixo:

SELECT *

FROM VW_Clientes_Australia_All_Info

ORDER BY CustomerID DESC;

Um outro recurso muito interessante do SQL Server, e que muitas


vezes pode ser utilizado na falta de uma view, são as Common Table
Expressions (CTE). As CTEs fornecem um mecanismo para definir uma
subconsulta que pode ser usada em outro lugar de uma query. Uma CTE é
definida no início de uma query, pode ser referenciada várias vezes dentro
da mesma. Dessa forma, fornecem um meio para dividir os problemas de
consulta em unidades menores e mais modulares.

As CTEs possuem algumas características peculiares, como:

 Têm escopo limitado para a execução da consulta externa. Quando a


consulta externa termina, a vida útil do CTE também termina;

 Exigem um nome para a expressão da tabela, além de nomes


exclusivos para cada uma das colunas referenciadas na cláusula
SELECT do CTE;

 Podem usar aliases para colunas;

 Várias CTEs podem ser definidas na mesma cláusula WITH;

 Suportam recursão, na qual a expressão é definida com uma


referência a si mesma;

143
 As seguintes cláusulas não podem ser usadas na CTE:

 ORDER BY (exceto quando uma cláusula TOP for especificada);

 INTO e a cláusula OPTION com hints.

SINTAXE DE CRIAÇÃO:

WITH <CTE_name>

AS ( <CTE_definition> )

EXEMPLO:

“Quantidade total de clientes e de pedidos, e a média, por bairro”

;WITH CTE1 AS ( SELECT Id_Bairro, Nm_Cliente, COUNT(Id_Pedido) AS Qt_Pedidos

FROM Clientes LEFT JOIN Pedidos

ON Clientes.Id_Cliente = Pedidos.Id_Pedido

GROUP BY Id_Bairro, Nm_Cliente

),

CTE2 AS ( SELECT Nm_Bairro, COUNT(Nm_Cliente) AS Qt_Clientes, SUM(Qt_Pedidos) AS


Qt_Pedidos

FROM Bairro LEFT JOIN CTE1

ON Bairro.Id_Bairro = CTE1.Id_Bairro

GROUP BY Nm_Bairro

SELECT Nm_Bairro, Qt_Clientes, Qt_Pedidos, CAST(Qt_Pedidos AS NUMERIC(15, 2)) / Qt_Clientes AS


Media

FROM CTE2;

CTE Recursiva:

;WITH Estrut_Hierarquia AS

( -- Nível 1 (Âncora)

SELECT Id_Empregado, Nm_Empregado, Id_Superior, 1 AS Nivel

144
FROM Funcionario

WHERE Id_Superior IS NULL

UNION ALL

-- Níveis 2-N

SELECT A.Id_Empregado, A.Nm_Empregado, A.Id_Superior, B.Nivel + 1 AS Nivel

FROM Funcionarios A

JOIN Estrut_Hierarquia B ON A.Id_Superior = B.Id_Empregado

Figura 100 – SELECT * FROM Estrut_Hierarquia.

Fonte: Gustavo (2019).

11.2. Stored Procedures


Um procedimento armazenado (stored procedure) é um recurso da
Linguagem SQL, criado (compilado) como um objeto no banco de dados, que
encapsula um conjunto de instruções SQL. Diferentemente das views, que
apenas encapsulam instruções SELECT, as procedures podem incluir uma

145
gama mais ampla de instruções SQL, como UPDATE, INSERT e DELETE, além
de instruções SELECT. Além dessas instruções, podem ser usadas
instruções de lógica de processamento, controle de fluxos, testes
condicionais, variáveis e instruções para tratamento de erros na execução
da procedure. As procedures podem possuir parâmetros de entrada e saída,
além de um valor de retorno.

Para criar um procedimento armazenado, é usado o comando


CREATE PROCEDURE da classe DDL da Linguagem SQL. De forma análoga
aos outros tipos de objetos, para alterar uma procedure usa-se o comando
ALTER PROCEDURE e, para excluir, o comando DROP PROCEDURE. Para
executar uma procedure, é usado o comando EXECUTE (ou simplesmente
EXEC) da classe DML.

Para exemplificarmos, imagine que ao invés de criarmos a view para


listar o ID e o Número da Conta dos clientes que são da Austrália,
desejássemos criar uma view. O código dessa view seria algo como o
mostrado abaixo, podendo inclusive já conter a cláusula ORDER BY (não
permitida no código da view):

CREATE PROCEDURE SP_Clientes_Australia AS

BEGIN

SELECT CustomerID, AccountNumber

FROM Sales.Customer

WHERE TerritoryID IN (

SELECT TerritoryID

FROM Sales.SalesTerritory

WHERE Name ='Australia'

ORDER BY CustomerID DESC

146
END;

Em termos de benefícios, os do uso de procedimentos armazenados


vão bem mais além do que os benefícios provenientes do uso de views.
Dentre esses benefícios, podemos citar:

 Mais segurança para os objetos do banco de dados: os usuários


podem possuir permissão para executar uma determinada
procedure, sem ter permissão para acessar diretamente os objetos
que a procedure acessa.

 Programação modular de fácil manutenção: a lógica é criada uma


vez, no código da procedure, e depois reutilizada várias vezes, em
diversos módulos da aplicação ou até mesmo em aplicações
diferentes, bastando fazer uma chamada à procedure. A manutenção
é mais fácil, pois se houver necessidade de alteração de código, só é
preciso alterar a procedure em questão, e não o código da aplicação
(ou de todas as aplicações que estiverem usando o código sem ser
via procedure).

 Redução do tráfico de rede: se a comunicação entre a aplicação e o


servidor de banco de dados for feita através de uma rede de dados,
o envio de uma linha de código (EXEC Nome_da_Procedure) é bem
menor (menos bytes) e bem mais rápida de ser enviada para o banco
de dados executar, do que várias linhas de código com instruções
SQL.

 Performance: quando uma instrução SQL é executada, a maioria dos


SGBDs cria um plano de execução para ela, relacionando os índices
indicados para o acesso aos dados. Esse plano de execução
representa a maneira mais eficiente para se executar a instrução
naquele momento. Esse processo, chamado de compilação, pode
aumentar significativamente o tempo de processamento para a

147
execução de instruções SQL. Para as procedures, toda primeira vez
que elas são executadas, o mecanismo de banco de dados compila o
código e cria um plano de execução da mesma maneira que o faria
para uma instrução SQL isolada, mas depois armazena e reutiliza
esse plano da procedure nas execuções seguintes. Como as
execuções seguintes usam esse plano de execução pré-compilado
ao invés de gerar um novo plano, o tempo necessário para executar
a procedure é reduzido, quando comparado com o mesmo código
executado sem ser via procedure.

Uma possibilidade muito interessante para se trabalhar com


procedures, é nas operações de inserção, atualização e deleção de dados,
onde pode-se, além de evitar acesso direto às tabelas, garantir várias
consistências e verificações através do código da procedure. Para viabilizar
isso, a linguagem SQL fornece o recurso de passagem de parâmetros para
as procedures.

No exemplo abaixo, podemos ver o código da procedure recebendo


os parâmetros, que serão os valores das colunas para inserir um novo
departamento na tabela Department:

CREATE PROCEDURE SP_Insere_Departamento

--Parâmetros de entrada e seus tipos de dados

--@DepartmentID smallint => não é necessário (coluna IDENTITY)

@NAme nvarchar(50),

@GroupName nvarchar(50)

--@ModifiedDate datetime => possui um default = getdate()

AS

BEGIN

--Exibindo no output os valores que serão inseridos

PRINT @NAme + ' ' + @GroupName;

148
--Inserindo os valores dos parâmetros de entrada na tabela

INSERT INTO HumanResources.Department

VALUES (@NAme, @GroupName, DEFAULT);

END;

--Execução da procedure passando os valores a serem inseridos:

EXEC SP_Insere_Departamento @Name='EAD', @GroupName='Education'

11.3. Functions
Assim como uma procedure, uma function é armazenada como um
objeto persistente (compilado) no banco de dados, mas possuindo algumas
diferenças fundamentais entre elas, como as mostradas abaixo:

Função (User Defined Function) Stored Procedure


A função deve retornar um valor. Procedure pode ou não retornar valores.
Permitirá apenas instruções SELECT, não
Pode ter instruções de seleção e instruções
permitirá usar outras instruções DML
DML, como inserir, atualizar e excluir.
(INSERT / UPDATE / DELETE).
Transações não são permitidas dentro de
Transações são permitidas.
funções.
Stored Procedures não podem ser chamadas
Procedures podem ser chamadas de funções.
de função.

Procedures não podem ser chamadas nas


As funções podem ser chamadas a partir de
instruções Select / Where / Having e assim
uma instrução SELECT.
por diante.

Um dos tipos de funções, conhecida como TVF (Table-Value


Function), possui várias propriedades em comum com as views, mas aceita
parâmetros de entrada, podendo consultá-los na instrução SELECT do seu
código. Em linhas gerais, a TVF encapsula uma única instrução SELECT,
retornando uma tabela virtual para a query, como mostrado a seguir.

149
SINTAXE DE CRIAÇÃO:

CREATE FUNCTION <name> (@<parameter_name> AS <data_type>, ...)

RETURNS TABLE AS

RETURN (<SELECT_expression>);

O exemplo a seguir cria uma function, que utiliza um parâmetro de


entrada para controlar quantas linhas são retornadas pelo operador TOP:

CREATE FUNCTION TopNProdutos (@qtde AS INT)

RETURNS TABLE AS

RETURN (SELECT TOP (@qtde) productid, name, ListPrice

FROM Production.Products

ORDER BY ListPriceDESC);

CHAMADA À TVF: SELECT * FROM TopNProductos(3)

11.4. Triggers
Já as TRIGGERS (gatilhos) são objetos programáticos também
armazenados de forma compilada no banco de dados, que são disparados
automaticamente, mediante uma ação no banco de dados, instância ou
objeto.

Um dos tipos de triggers mais conhecido e usado é o DML TRIGGER.


Uma trigger DML é executada quando um INSER T, UPDATE ou DELETE
modifica os dados em uma tabela ou view (incluindo qualquer INSERT,
UPDATE ou DELETE que faz parte de uma instrução MERGE), podendo
consultar dados em outras tabelas. As DDL TRIGGERS são semelhantes às
triggers DML, com a diferença que são disparadas quando ocorrem eventos
DDL (CREATE, ALTER, DROP etc.). Há também as LOGON TRIGGERS, que

150
são uma forma especial de gatilho que dispara quando uma nova sessão é
estabelecida.

EXEMPLO DE DML TRIGGER:

CREATE TRIGGER TRG_Aviso ON Aluno

AFTER INSERT AS

EXEC msdb.dbo.sp_send_dbmail

@profile_name = 'Coordenador',

@recipients = '[email protected]',

@body = 'Novo aluno matriculado no curso',

@subject = 'Aviso de Novo Aluno';

GO

11.5. Linked Server e Query Distribuída


Em linhas gerais, uma query distribuída é uma consulta que executa
em mais de uma instância de banco de dados. Uma característica essencial
de uma query distribuída é a transparência da localização física dos dados,
ou seja, o usuário tem uma visão centralizada do acesso a esses dados.

Figura 101 – Query Distribuída.

Fonte: Sid Choudhury (2019).

151
O Linked Server (no Oracle, chamado de dblink) permite que uma
instância SQL Server leia dados de fontes de dados remotas e executem
comandos nos servidores de banco de dados remotos. Normalmente, os
linked server são configurados para permitir que o usuário execute uma
instrução T-SQL que inclua tabelas em outra instância do SQL Server ou em
outro produto de banco de dados, como Oracle. Além de acessar outros
bancos de dados, o linked server pode ser configurado para acessar dados
que estejam no Microsoft Access, no Excel e até mesmo na nuvem, como o
Azure CosmosDB.

Figura 102 – Linked Server.

Fonte: Microsoft (2019).

Nas aulas gravadas e nas demonstrações, veremos como criar um


linked server e como realizar uma query distribuída.

152
Referências
BERNARDI, Diogo Alencar. Técnicas de mapeamento objeto relacional.
DevMedia, 2008. Disponível em: https://www.devmedia.com.br/tecnicas-de-
mapeamento-objeto-relacional-revista-sql-magazine-40/6980. Acesso em:
14 jan. 2022.

CELEPAR. Guia para Mapeamento Objeto Relacional Metodologia Celepar.


Agosto 2009.

CHAMBERLIN, Donald D. et al. A History and Evaluation of System R. In:


Communications of the ACM, São Jose, Califórnia, v. 24, n. 10, out. 1981, p.
632-646. Disponível em:
https://people.eecs.berkeley.edu/~brewer/cs262/SystemR.pdf. Acesso em:
14 jan. 2022.

CHAMBERLIN, Donald D.; BOYCE, Raymond F. SEQUEL: A Structured English


Query Language. Disponível em:
http://www.joakimdalby.dk/HTM/sequel.pdf. Acesso em: 14 jan. 2022.

CHEN, Peter. Modelagem de Dados. São Paulo: McGraw-Hill, Makron, 1990.

CHEN, Peter. Peter Chen Home Page at Louisiana State University (LSU).
Disponível em: https://www.csc.lsu.edu/~chen. Acesso em: 28 out. 2021.

CHEN, Peter. The Entity-Relationship Model - Toward a Unified View of Data.


Massachusetts: Center for Information Systems Research, n. 30, mar. 1977.
Disponível em:
https://dspace.mit.edu/bitstream/handle/1721.1/47432/entityrelationshx0
0chen.pdf. Acesso em: 14 jan. 2022.

CODD, Edgar F. A Relational Model of Data for Large Shared Data Banks. In:
Communications of the ACM, v. 13, n. 6, jun. 1970, p. 377-387. Disponível

153
em:
https://github.com/dmvaldman/library/blob/master/computer%20science/
Codd%20-
%20A%20Relational%20Model%20of%20Data%20for%20Large%20Shar
ed%20Data%20Banks.pdf. Acesso em: 14 jan. 2022.

CODD, Edgar F. The Relational Model for Database Management: Version 2.


United States Of America: Addison Wesley Publishing Company, 1990.

COUGO, Paulo. Modelagem Conceitual e Projeto de Banco de Dados. 14ª


reimpressão. Rio de Janeiro: Elsevier, 1997.

DICIONÁRIO da Língua Portuguesa Brasileira. Michaelis, c2022. Disponível


em: https://michaelis.uol.com.br/moderno-portugues. Acesso em: 14 jan.
2022.

FLYWAY. Disponível em: https://flywaydb.org/. Acesso em: 14 jan. 2022.

HILLS, Ted. NOSQL and SQL Data Modeling: Bringing Together Data,
Semantics, and Software. Technics Publications, 2016.

INTRODUCTION to NOSQL Databases Tutorial. Simplilearn. Disponível em:


https://www.simplilearn.com/introduction-to-nosql-databases-tutorial-
video. Acesso em: 28 out. 2021.

KELECHAVA, Brad. The SQL Standard – ISO/IEC 9075:2016 (ANSI X3. 135).
ANSI – American National Standards Institute, 5 out. 2018. Disponível em:
https://blog.ansi.org/2018/10/sql-standard-iso-iec-9075-2016-ansi-x3-
135/. Acesso em: 14 jan. 2022.

KIM, James. UnQK Query Language Unveiled by Couchbase and SQLite.


Couchbase, 29 jul. 2011. Disponível em: https://www.couchbase.com/press-
releases/unql-query-language. Acesso em: 14 jan. 2022.

154
KORTH, Henry F. Sistema de bancos de dados. 3ª ed. São Paulo: McGraw-Hill,
1999.

MACHADO, Felipe Nery Rodrigues; ABREU, Maurício Pereira de. Projeto de


Banco de Dados: uma visão prática. 13ª ed. São Paulo: Érica, 1996.

MACORATTI, José Carlos. Node.js – Apresentando e usando o Sequelize


(acesso ao MySQL). Macoratti.net. Disponível em:
http://www.macoratti.net/17/01/node_sequelize1.html. Acesso em: 14 jan.
2022.

MICROSOFT SQL Documentation. Microsoft, c2022. Disponível em:


https://docs.microsoft.com/en-us/sql/?view=sql-server-2017. Acesso em: 28
out. 2021.

MICROSOFT SQL Server 2017. Microsoft, c2022. Disponível em:


https://www.microsoft.com/pt-br/sql-server/sql-server-2017. Acesso em: 14
jan. 2022.

MONQUEIRO, Julio Cesar Bessa. Programação Orientada a Objetos: uma


introdução. Hardware.com.br, 29 out. 2007. Disponível em:
https://www.hardware.com.br/artigos/programacao-orientada-objetos.
Acesso em: 14 jan. 2022.

NAVATHE, Shamkant B.; ELSMARI, Ramez. Sistemas de Banco de Dados. 4


ed. São Paulo: Pearson Addison Wesley, 2005.

NOSQL Database Org. Disponível em: http://nosql-database.org/. Acesso em:


14 jan. 2022.

RODRIGUES, Joel. Entity Framework: Como fazer seu primeiro Mapeamento


Objeto-Relacional. DevMedia, 2007. Disponível em:
https://www.devmedia.com.br/entity-framework-como-fazer-seu-primeiro-
mapeamento-objeto-relacional/38756. Acesso em: 14 jan. 2022.

155
ROEBUCK, Kevin. Object-Relational Mapping (Orm): High-Impact Strategies.
Paperback, 2011.

SEQUELIZE. Disponível em: http://docs.sequelizejs.com/. Acesso em: 14 jan.


2022.

SHALER, Sally; MELLOR, Stephen J. Object Oriented Systems Analysis:


Modeling the World in Data. 1. ed. Prentice Hall, 1988.

STROZZI, Carlo. NoSQL: A non-SQL RDBMS. NoSQL Home Page, c2010.


Disponível em: http://www.strozzi.it/cgi-
bin/CSA/tw7/I/en_US/nosql/Home%20Page. Acesso em: 14 jan. 2022.

TOP 9 Object Databases. Pat Research, c2013-2021. Disponível em:


https://www.predictiveanalyticstoday.com/top-object-databases. Acesso
em: 14 jan. 2022.

UNQL ORG. Disponível em:


http://unql.sqlite.org/index.html/wiki?name=UnQL. Acesso em: 14 jan. 2022.

VERSIONSQL. Disponível em: https://www.versionsql.com/. Acesso em: 14


jan. 2022.

156

Você também pode gostar