Aula 01 — Revisão de SQL: do modelo relacional ao banco funcionando

Projeto de Banco de Dados

Você já escreveu dezenas de consultas. Nesta disciplina a pergunta muda de lado: o que acontece do outro lado da conexão quando você aperta executar? Hoje recompomos a base de SQL sobre a qual o semestre inteiro será construído.

Curso

Engenharia de Software

Carga horária

80 horas

SGBD

PostgreSQL

Encontros

Sextas-feiras

1. Como a disciplina funciona

Até aqui, banco de dados apareceu como ferramenta: modelar tabelas, escrever consultas, usar o ORM. Esta disciplina abre a caixa. O objeto de estudo passa a ser o próprio sistema gerenciador: como ele guarda os dados em disco, como garante que uma transferência bancária não perca dinheiro no meio, e por que a mesma consulta às vezes leva 3 milissegundos e às vezes 3 segundos.

É uma disciplina prática. A maior parte dos encontros tem metade ou mais do tempo em laboratório, e a exposição serve para dar sentido ao que será feito no mesmo dia.

1 · Arquitetura do SGBD

Estrutura física e armazenamento; cluster, databases e schemas; tablespaces; estruturas de arquivos.

2 · Transações e concorrência

ACID; MVCC; recuperação; controle de concorrência.

3 · Processamento de consultas

Indexação; ciclo de vida da consulta; planos de execução; algoritmos de junção; EXPLAIN e ANALYZE; tuning.

4 · Novas tecnologias

Tipos de banco de dados; mineração de dados; Data Warehousing e OLAP; bancos distribuídos.

Avaliação

ComponenteComo se compõe
MB1P1 (0 a 7,0) + MT1 (0 a 3,0)
MB2P2 (0 a 7,0) + MT2 (0 a 3,0)
Média final(MB1 + MB2) ÷ 2, com frequência mínima de 75%

MT1 e MT2 vêm dos trabalhos e das atividades entregues ao fim de cada encontro.

Toda aula tem entrega

Ao fim de cada encontro há uma atividade curta, feita no laboratório e enviada pelo Classroom antes de você sair da sala. Ela não é para levar para casa, e quem não terminar entrega o que fez. Isso significa, na prática, que sair mais cedo custa nota.

Na próxima aula cada um vai montar a própria máquina virtual Linux com PostgreSQL instalado, configurar o acesso externo e conectar de fora. Hoje não se instala nada: o pgAdmin já está nas máquinas do laboratório.

Antes de começar: o ambiente

Todo o SQL desta página é executado no pgAdmin 4, já instalado nas máquinas do laboratório. Esta página é o material de consulta: o comando fica aqui, com botão de copiar, e você executa lá.

Tutorial do ambiente

O passo a passo completo do pgAdmin, do primeiro clique à primeira consulta. Baixar PDF

Guia do desafio

As oito etapas do desafio, com o que conferir em cada uma. Baixar PDF

Script do banco

Cria as tabelas e os dados de uma vez, para quem faltou ou se perdeu. Baixar .sql

Os quatro primeiros passos

  1. Abra o pgAdmin 4 pelo menu. A primeira abertura demora alguns segundos e a janela pode ficar em branco por um instante: é normal, não clique várias vezes no ícone. Na primeira vez ele pede uma senha mestra, que não é a senha do banco — é só para ele guardar as suas conexões. Anote a que você escolher.
  2. Conecte no servidor. Na árvore à esquerda, clique no servidor listado em Servers e informe a senha do usuário postgres. Se não houver servidor nenhum, chame o professor: o pgAdmin sozinho é só o painel, e precisa de um PostgreSQL rodando para conversar.
  3. Crie o seu banco. Botão direito em Databases → Create → Database…, com o nome biblioteca. Não trabalhe dentro do banco postgres, que é o de manutenção do servidor.
  4. Abra a janela de consulta. Com o banco biblioteca selecionado, use Tools → Query Tool ou Alt+Shift+Q. É aqui que você escreve SQL.
O que fazerComo
Executar tudo o que está no editorF5, ou o botão ▶
Executar só um trechoselecione com o mouse e aperte F5
Salvar o seu arquivoCtrl + S
Abrir um arquivo .sqlCtrl + O, ou o ícone de pasta

A linha destacada é a mais útil: você vai acumular comandos na mesma janela, e selecionar só o que quer rodar evita reexecutar tudo a cada teste.

Confira em qual banco você está

O nome do banco aparece na aba da janela de consulta. Escrever SQL na janela errada e depois não entender por que a tabela "sumiu" é o tropeço mais comum do primeiro dia.

Salve desde o começo, não no fim

Mantenha uma janela com todos os comandos que você escreveu, na ordem, e salve com Ctrl+S como aula01-seusobrenome.sql. Esse arquivo é a sua entrega de hoje, e é o que você vai rodar dentro da máquina virtual na aula 02. Máquina de laboratório trava e é usada por outra turma depois de você: guarde uma cópia em pendrive, e-mail ou Drive.

Se você faltou, chegou atrasado ou quer refazer em casa

O script abaixo cria as tabelas e os dados usados das seções 7 em diante, de uma vez só. Ele também está disponível como arquivo: baixar banco-aula01.sql. No pgAdmin, abra com Ctrl+O e execute com F5.

banco-aula01.sql — o cenário completo
Loading...
DROP TABLE IF EXISTS livro;
DROP TABLE IF EXISTS autor;

CREATE TABLE autor (
  id         serial PRIMARY KEY,
  nome       text NOT NULL,
  pais       varchar(50),
  nascimento date
);

CREATE TABLE livro (
  id         serial PRIMARY KEY,
  titulo     text NOT NULL,
  isbn       varchar(20) UNIQUE,
  ano        integer CHECK (ano > 1400),
  disponivel boolean DEFAULT true,
  autor_id   integer NOT NULL REFERENCES autor(id)
);

INSERT INTO autor (nome, pais, nascimento) VALUES
  ('Machado de Assis',       'Brasil',   '1839-06-21'),
  ('Clarice Lispector',      'Brasil',   '1920-12-10'),
  ('Graciliano Ramos',       'Brasil',   '1892-10-27'),
  ('Jorge Amado',            'Brasil',   '1912-08-10'),
  ('Gabriel García Márquez', 'Colômbia', '1927-03-06'),
  ('Autor Sem Livro',        'Brasil',   NULL);

INSERT INTO livro (titulo, isbn, ano, autor_id) VALUES
  ('Dom Casmurro',        '978-85-01', 1899, 1),
  ('Memórias Póstumas',   '978-85-02', 1881, 1),
  ('Quincas Borba',       NULL,        1891, 1),
  ('A Hora da Estrela',   '978-85-03', 1977, 2),
  ('Vidas Secas',         '978-85-04', 1938, 3),
  ('Capitães da Areia',   '978-85-05', 1937, 4),
  ('Cem Anos de Solidão', '978-85-06', 1967, 5);

Só use o script se precisar

Digitar os comandos é lento, e é exatamente por isso que funciona. Você aprende a escrever SQL escrevendo SQL, não colando. O script existe como rede de segurança, não como atalho.

2. Antes do SQL: o que é uma tabela

Uma tabela é um conjunto de linhas que compartilham as mesmas colunas. Os nomes formais aparecem na bibliografia e vale reconhecê-los quando surgirem.

Termo do dia a diaTermo formalO que é
TabelaRelaçãoa estrutura inteira
LinhaTuplaum registro individual
ColunaAtributoum campo, com tipo fixo
TipoDomínioo conjunto de valores que a coluna aceita

Todos os valores de uma coluna são do mesmo tipo. Essa garantia é o que separa um banco de uma planilha, e é o que permite comparar, ordenar e indexar sem precisar verificar valor por valor.

As duas chaves

Chave primária

Identifica cada linha de forma única. Não repete e não aceita vazio. Toda tabela deve ter uma.

Chave estrangeira

Aponta para a chave primária de outra tabela e cria o vínculo entre as duas.

Por que a chave estrangeira importa

É ela que impede o banco de registrar um empréstimo de um livro que não existe. Sem a chave estrangeira declarada, o vínculo entre as tabelas existe apenas na cabeça de quem escreveu o código, e some no primeiro erro de digitação.

3. Criando o banco e a primeira tabela

O comando que cria um banco é direto, e é o único da aula que você não vai executar aqui: o executor já coloca você dentro de um banco pronto.

CREATE DATABASE biblioteca;

A tabela é onde as decisões começam. Copie o bloco abaixo para o pgAdmin, execute, e depois leia cada linha com calma: cada pedaço dela é uma escolha de projeto.

A primeira tabela
Loading...
DROP TABLE IF EXISTS livro;
DROP TABLE IF EXISTS autor;

CREATE TABLE autor (
  id         serial       PRIMARY KEY,
  nome       text         NOT NULL,
  pais       varchar(50),
  nascimento date
);

SELECT * FROM autor;
TrechoO que significa
ido nome da coluna
serialinteiro que se numera sozinho a cada inserção: 1, 2, 3…
PRIMARY KEYidentifica a linha; já implica NOT NULL e UNIQUE
texttexto de tamanho livre
NOT NULLnão aceita vazio; inserir sem nome dá erro
varchar(50)texto com limite de 50 caracteres
datesó data, sem hora

Zero linhas, e está certo

O SELECT devolveu nenhuma linha, mas a estrutura existe. Criar a tabela e povoar a tabela são operações separadas, e essa distinção vai reaparecer o semestre inteiro.

4. Escolhendo o tipo de cada coluna

O tipo não é detalhe de sintaxe. Ele define o que a coluna aceita, quanto ocupa e quais operações fazem sentido sobre ela.

TipoPara quêCuidado
integernúmeros inteiros
serialinteiro com numeração automáticause apenas na chave primária
numeric(10,2)dinheiro e medidas exatas10 dígitos, 2 depois da vírgula
real / floatponto flutuantenunca para dinheiro
texttexto sem limiteé o padrão no PostgreSQL
varchar(n)texto com limiteo limite é regra de negócio, não desempenho
booleanverdadeiro ou falsoaceita true, false e NULL
datedata
timestampdata e hora

A linha destacada merece demonstração. Rode isto no pgAdmin e olhe o resultado da soma:

Por que dinheiro não usa float
Loading...
SELECT (0.1::float8 + 0.2::float8)::text         AS soma_float,
       (0.1::numeric + 0.2::numeric)::text       AS soma_numeric,
       (0.1::float8 + 0.2::float8) = 0.3::float8 AS float_bate;

O float devolve 0.30000000000000004, e a comparação com 0.3 dá falso. Num cálculo isolado essa diferença é invisível. Veja o que ela faz somada, em mil lançamentos de um centavo:

Mil lançamentos de R$ 0,01
Loading...
SELECT sum(0.01::float8)::text  AS total_float,
       sum(0.01::numeric)::text AS total_numeric
FROM generate_series(1, 1000);

O centavo que ninguém acha

Deveriam ser R$ 10,00. Em float sai 9.999999999999831. Repare que não existe um lançamento errado para procurar: o erro está espalhado por todos os mil. É por isso que, em sistema financeiro, numeric é a única opção.

E não adianta trocar por real, que é menor — ele só demora mais a aparecer. sum(0.1::real) cem vezes dá 10.000002, e não 10.

5. Restrições: o banco defendendo os dados

Agora uma tabela com vínculo e com regras. Cada restrição declarada aqui é um tipo de dado errado que deixa de existir na base.

Tabela com restrições
Loading...
CREATE TABLE livro (
  id         serial       PRIMARY KEY,
  titulo     text         NOT NULL,
  isbn       varchar(20)  UNIQUE,
  ano        integer      CHECK (ano > 1400),
  disponivel boolean      DEFAULT true,
  autor_id   integer      NOT NULL REFERENCES autor(id)
);

INSERT INTO autor (nome, pais) VALUES ('Machado de Assis', 'Brasil');

SELECT id, nome FROM autor;
RestriçãoO que garante
PRIMARY KEYidentifica a linha; não repete e não é nula
UNIQUEnão repete, mas aceita nulo
NOT NULLnão aceita vazio
CHECK (…)a condição precisa ser verdadeira para a linha entrar
DEFAULTvalor usado quando você não informa nada
REFERENCESchave estrangeira: o valor precisa existir na outra tabela

Três tentativas que precisam falhar

No pgAdmin, selecione uma linha por vez e aperte F5, mantendo as outras duas comentadas. O erro é o resultado esperado: é o banco fazendo o trabalho dele.

Testando as restrições
Loading...
-- 1) não existe autor com id 999
INSERT INTO livro (titulo, ano, autor_id) VALUES ('Livro sem autor', 2020, 999);

-- 2) 1200 não passa no CHECK
-- INSERT INTO livro (titulo, ano, autor_id) VALUES ('Livro antigo', 1200, 1);

-- 3) falta o título, que é NOT NULL
-- INSERT INTO livro (ano, autor_id) VALUES (2020, 1);

Cada erro acima é um problema que não aconteceu

Sem essas restrições, as três linhas entrariam sem qualquer reclamação. O problema apareceria meses depois, num relatório que não fecha, e a essa altura ninguém mais consegue dizer quais registros estão errados nem desde quando.

6. Inserindo dados

Uma linha por vez, ou várias de uma vez. Repare que ninguém informa o id: o serial cuida disso.

Povoando as tabelas
Loading...
INSERT INTO autor (nome, pais, nascimento) VALUES
  ('Clarice Lispector',      'Brasil',   '1920-12-10'),
  ('Graciliano Ramos',       'Brasil',   '1892-10-27'),
  ('Jorge Amado',            'Brasil',   '1912-08-10'),
  ('Gabriel García Márquez', 'Colômbia', '1927-03-06');

INSERT INTO livro (titulo, isbn, ano, autor_id) VALUES
  ('Dom Casmurro',        '978-85-01', 1899, 1),
  ('A Hora da Estrela',   '978-85-03', 1977, 2),
  ('Vidas Secas',         '978-85-04', 1938, 3),
  ('Capitães da Areia',   '978-85-05', 1937, 4),
  ('Cem Anos de Solidão', '978-85-06', 1967, 5);

SELECT id, nome, pais FROM autor ORDER BY id;

7. Consultando

O SELECT é o comando que você mais vai escrever na vida profissional, e o único que ganha uma unidade inteira desta disciplina.

Filtros
Loading...
SELECT titulo, ano FROM livro WHERE ano > 1950;

-- experimente trocar por uma destas:
-- SELECT titulo FROM livro WHERE ano BETWEEN 1900 AND 1950;
-- SELECT titulo FROM livro WHERE titulo LIKE '%Solidão%';
-- SELECT titulo FROM livro WHERE autor_id IN (1, 2);
-- SELECT titulo FROM livro WHERE isbn IS NULL;
OperadorUso
= <> > < >= <=comparação
BETWEEN a AND bfaixa, incluindo os dois extremos
LIKEpadrão de texto: % é qualquer coisa, _ é um caractere
IN (…)está na lista
IS NULL / IS NOT NULLvazio ou preenchido
AND OR NOTcombinação de condições

= NULL nunca funciona

NULL não é um valor: é a ausência de um. Nada é igual a uma ausência, nem outra ausência. A comparação devolve nulo em vez de verdadeiro ou falso, então a linha jamais aparece no resultado, e você recebe uma lista vazia sem nenhuma mensagem de erro. Use sempre IS NULL. É o erro de SQL mais comum que existe, e o mais silencioso.
A diferença, medida
Loading...
SELECT count(*) AS com_igual  FROM livro WHERE isbn = NULL;
SELECT count(*) AS com_is_null FROM livro WHERE isbn IS NULL;

Ordenar e limitar fecham o repertório básico. Sem ORDER BY não existe garantia nenhuma de ordem, mesmo que o resultado pareça consistente nos seus testes.

Ordenação
Loading...
SELECT titulo, ano FROM livro ORDER BY ano DESC LIMIT 3;

8. JOIN: juntando as tabelas

O autor_id do livro é um número, e ninguém quer ler número em relatório. O JOIN troca o número pelo dado.

INNER JOIN
Loading...
SELECT l.titulo, a.nome AS autor, l.ano
FROM livro l
JOIN autor a ON a.id = l.autor_id
ORDER BY a.nome;

A palavra INNER é opcional: JOIN sozinho já significa isso. Os apelidos de tabela, l e a, são como se escreve no dia a dia.

A diferença que decide o relatório

O cenário tem um autor cadastrado sem nenhum livro. Rode o bloco abaixo, depois troque LEFT JOIN por JOIN e execute de novo. Conte as linhas nas duas versões.

LEFT JOIN contra INNER JOIN
Loading...
SELECT a.nome, l.titulo
FROM autor a
LEFT JOIN livro l ON l.autor_id = a.id
ORDER BY a.nome;
INNER JOINLEFT JOIN
Trazsó o que casa dos dois ladostudo da esquerda, casando ou não
Quem não casadesaparece do resultadoaparece com NULL nas colunas da direita
Serve paracruzar dados existentesencontrar o que está faltando

Onde isso vira erro de verdade

Um relatório de "quantos livros cada autor tem" escrito com INNER JOIN esconde justamente os autores com zero livro, que muitas vezes são exatamente os que a pergunta queria encontrar. O resultado sai sem erro, com aparência correta, e a decisão tomada em cima dele está errada. A pergunta de negócio é que determina qual dos dois usar.

9. Agrupando e contando

Agregações sobre a tabela inteira
Loading...
SELECT count(*)        AS total_livros,
       min(ano)        AS mais_antigo,
       max(ano)        AS mais_recente,
       round(avg(ano)) AS ano_medio
FROM livro;

O GROUP BY faz a mesma conta, mas por grupo. Note o LEFT JOIN: sem ele, o autor sem livro sumiria da lista em vez de aparecer com zero.

Contagem por autor
Loading...
SELECT a.nome, count(l.id) AS quantos_livros
FROM autor a
LEFT JOIN livro l ON l.autor_id = a.id
GROUP BY a.nome
ORDER BY quantos_livros DESC;
HAVING filtra depois de agrupar
Loading...
SELECT a.nome, count(l.id) AS quantos
FROM autor a
JOIN livro l ON l.autor_id = a.id
GROUP BY a.nome
HAVING count(l.id) > 1;

WHERE e HAVING é questão de momento

O WHERE filtra linhas antes do agrupamento. O HAVING filtra grupos depois dele. É por isso que não se usa count() dentro do WHERE: no momento em que ele roda, o grupo ainda não existe.

Duas contagens que parecem iguais e não são. A diferença entre elas é exatamente a quantidade de nulos da coluna:

count(*) contra count(coluna)
Loading...
SELECT count(*)    AS todas_as_linhas,
       count(isbn) AS com_isbn
FROM livro;

10. Alterando e apagando

UPDATE e DELETE com WHERE
Loading...
UPDATE livro SET disponivel = false WHERE id = 1;

SELECT id, titulo, disponivel FROM livro WHERE id = 1;

O erro mais caro do SQL

Os dois comandos abaixo são válidos:

UPDATE livro SET disponivel = false;   -- muda TODAS as linhas
DELETE FROM livro;                     -- apaga TODAS as linhas

O banco não pergunta nada, não avisa e faz exatamente o que foi mandado. O hábito que evita o prejuízo é simples e vale para o resto da carreira: escreva primeiro o SELECT com o mesmo WHERE, confira quais linhas voltaram, e só então troque o SELECT * por UPDATE ou DELETE.

Mudanças de estrutura usam ALTER TABLE. E apagar tabela tem ordem: primeiro quem aponta, depois quem é apontado. É a inversa da ordem de criação.

ALTER e DROP
Loading...
ALTER TABLE livro ADD COLUMN paginas integer;
ALTER TABLE livro DROP COLUMN paginas;

-- esta linha falha: livro depende de autor
DROP TABLE autor;

-- a ordem correta seria:
-- DROP TABLE livro;
-- DROP TABLE autor;

11. As cinco famílias do SQL

Os nomes valem porque a disciplina se organiza em torno deles. Hoje você usou as três primeiras; as outras duas são assunto do semestre.

SiglaFunçãoComandosOnde volta
DDLDefine a estruturaCREATE · ALTER · DROP · TRUNCATEUnidade 1
DMLMexe nos dadosINSERT · UPDATE · DELETEUnidade 2
DQLConsultaSELECTUnidade 3
DCLControla acessoGRANT · REVOKEAula 05
TCLControla transaçãoBEGIN · COMMIT · ROLLBACKUnidade 2

Na próxima aula

Na aula 02 cada um monta uma máquina virtual Linux com PostgreSQL instalado, configura o acesso externo pelos arquivos postgresql.conf e pg_hba.conf, e conecta nesse servidor a partir de outra máquina. É o primeiro passo para administrar um banco em servidor de verdade, inclusive em nuvem.

12. Desafio: sistema de chamados

Uma empresa de manutenção de equipamentos controla os chamados dos clientes numa planilha. Três coisas já deram errado: chamado atribuído a técnico que não trabalha mais lá, cliente cadastrado duas vezes com grafias diferentes, e um relatório de produtividade que ninguém consegue fechar porque os valores estão escritos em texto livre.

Modele isso como banco de dados.

Parte 1 · Modelagem

cliente

Identificador próprio, nome obrigatório, cidade e um campo de cadastro que não pode se repetir entre clientes.

tecnico

Identificador próprio, nome obrigatório, especialidade e um booleano dizendo se ainda está ativo, começando como verdadeiro.

chamado

Identificador, descrição obrigatória, data de abertura, valor cobrado e as ligações com cliente e técnico. O valor não pode ser negativo.

O conjunto precisa ter, no mínimo, um NOT NULL, um UNIQUE, um CHECK e um DEFAULT, além das chaves.

Parte 2 · Dados

Quatro clientes em pelo menos duas cidades, três técnicos sendo um inativo e um sem nenhum chamado, e oito chamados distribuídos de forma desigual, com pelo menos um sem valor preenchido. A distribuição desigual não é capricho: sem ela as consultas da parte 3 devolvem tudo igual e não provam nada.

Parte 3 · Consultas

  1. Todos os chamados com o nome do cliente e o nome do técnico, em vez dos números.
  2. Quantos chamados cada técnico atendeu. O técnico sem chamado nenhum precisa aparecer na lista, com zero.
  3. O valor total cobrado por cliente, do maior para o menor.
  4. Os chamados abertos por clientes de uma cidade específica, à sua escolha.
  5. Os técnicos com mais de dois chamados atendidos.
  6. Quantos chamados estão sem valor preenchido, em uma única consulta.
  7. O chamado mais caro, com o nome do cliente.
  8. A média de valor por técnico, considerando apenas os técnicos ativos.

Parte 4 · Três perguntas

  1. Na questão 2, qual tipo de JOIN você usou e por quê? O que aconteceria com o resultado se você usasse o outro?
  2. Volte ao problema da empresa. Qual restrição que você criou impede cada um dos três erros que eles tiveram? Se algum não for impedido pelo banco, diga qual e explique por quê.
  3. Um colega sugeriu guardar o valor cobrado como text, porque assim daria para escrever "a combinar" quando não há preço fechado. Responda a ele.
Use o espaço abaixo para trabalhar. Ao terminar, envie um arquivo .sql pelo Classroom com os comandos na ordem em que rodaram e as respostas em comentário, nomeado aula01-seusobrenome.sql. Entrega no fim da aula: quem não terminar envia o que fez.
Ponto de partida do desafio
Loading...
-- Parte 1: crie as três tabelas aqui, na ordem certa.
-- Lembre: chamado referencia as outras duas, então vem por último.

CREATE TABLE cliente (
  id   serial PRIMARY KEY
  -- continue
);

Onde a turma costuma travar

  • Questão 2 resolvida com INNER JOIN: o técnico sem chamado desaparece e a lista sai com um técnico a menos, sem erro nenhum.
  • WHERE count(...) na questão 5. Agregação filtra com HAVING.
  • Criar chamado antes de cliente e tecnico: a chave estrangeira precisa que a tabela apontada já exista.

13. Perguntas para fixação e debate

Sem gabarito. Servem para você testar se entendeu, e para a discussão em sala.
  1. Uma coluna UNIQUE e uma coluna PRIMARY KEY parecem fazer a mesma coisa. Qual é a diferença, e em que situação ela aparece na prática?
  2. Por que o resultado de uma consulta sem ORDER BY não pode ser considerado ordenado, mesmo quando parece consistente em todos os seus testes?
  3. Se uma tabela tem 100 linhas e a coluna email tem 30 valores nulos, quanto devolvem count(*) e count(email)? Por que a diferença existe?
  4. Você precisa apagar um autor que tem livros cadastrados. O banco recusa. Quais são as saídas possíveis, e qual delas você escolheria num sistema em produção?
  5. Em que situação usar varchar(50) em vez de text é uma boa decisão de projeto? E em que situação é apenas hábito herdado de outro banco?
  6. O comando DELETE FROM cliente; foi executado por engano numa base de produção. O que aconteceu, e o que precisaria existir para recuperar os dados? Guarde a resposta: o assunto volta na aula 09.

📚 Estudo desta aula

  • MACHADO, Felipe Nery R. Banco de Dados: Projeto e Implementação. São Paulo: Saraiva, 2020. Modelo relacional e linguagem SQL
  • CARDOSO, G. C.; CARDOSO, V. M. Linguagem SQL, fundamentos e práticas. São Paulo: Saraiva, 2013. DDL, DML e consultas
  • HEUSER, Carlos A. Projeto de banco de dados. Porto Alegre: Grupo A, 2011. Modelo relacional e restrições de integridade

📖 Leitura complementar

  • SILBERSCHATZ, Abraham. Sistema de Banco de Dados. Rio de Janeiro: Grupo GEN, 2020.
  • POSTGRESQL GLOBAL DEVELOPMENT GROUP. PostgreSQL Documentation. Disponível em postgresql.org/docs. The SQL Language; Data Types

O executor de SQL desta página roda um PostgreSQL real compilado para WebAssembly, dentro do seu navegador. Nada é enviado a servidor, e o banco desaparece quando a aba é fechada.