PostgreSQL - SQL Básico
PostgreSQL - SQL Básico
Juliano Atanazio
2017-03-23
PostgreSQL - SQL Básico
Sobre esta Obra...
Desde que fiz meu primeiro curso de PostgreSQL já havia despertado em mim um
desejo muito forte de um dia também ministrar o curso.
Mas junto com meu desejo de ministrar o curso havia um desejo muito forte
também de eu fazer meu próprio material de forma que fosse fácil de entender e com
muitos exercícios para praticar e entender a teoria.
A primeira tentativa foi baseada no PostgreSQL 8.4, cuja estrutura era a tradução
da documentação oficial conforme o assunto abordado, mas com uma diagramação ainda
bem insatisfatória.
Nesta obra ainda a estrutura é fortemente baseada na tradução da documentação
oficial, mas com diagramação bem mais moderna e fácil de entender. Claro que muitas
coisas há muito de minhas próprias palavras, porém o intuito desta obra é trazer uma
abordagem prática com exemplos fáceis de serem executados.
Esta obra não tem pretensão alguma de substituir a documentação oficial. A
documentação oficial do PostgreSQL está entre as melhores que já tive a oportunidade de
conhecer, muito bem organizada, bem como a documentação do FreeBSD.
De forma geral os assuntos tratados são diversas formas de instalação,
configuração, backup, migração de versões e outros assuntos relacionados ao sistema
gerenciador de banco de dados orientado a objetos PostgreSQL.
Àqueles que tiverem críticas, sugestões ou elogios, estou à disposição para que a
cada versão além de conteúdo acrescentado, aperfeiçoamento de exemplos e textos bem
como correção de eventuais erros.
Um grande abraço e boa leitura e bom curso, pois você escolheu o melhor SGBD
do mundo! :D
Juliano Atanazio
[email protected]
4
Dedicatórias
7
6.2 Valor Padrão (DEFAULT).........................................................................................90
6.3 CHECK.....................................................................................................................91
6.4 NOT NULL................................................................................................................92
6.5 UNIQUE....................................................................................................................93
6.6 A Cláusula [NOT] DEFERRABLE.............................................................................94
6.7 Chave Primária / Primary Key..................................................................................96
6.7.1 Chave Primária Composta................................................................................98
6.8 Chave Estrangeira / Foreign Key.............................................................................99
6.8.1 Cláusulas ON DELETE / ON UPDATE...........................................................101
7 SELECT – Consultas (Queries).....................................................................................103
7.1 Sobre SELECT.......................................................................................................104
7.2 DISTINCT...............................................................................................................106
7.3 LIMIT e OFFSET....................................................................................................107
7.4 A Cláusula WHERE................................................................................................108
7.5 A Cláusula ORDER BY...........................................................................................113
7.6 CASE: Um IF Disfarçado........................................................................................115
7.7 A Função coalesce.................................................................................................117
7.8 A Função nullif........................................................................................................118
7.9 As Funções greatest e least...................................................................................119
7.10 O Comando TABLE..............................................................................................120
8 DML: Inserir, Alterar e Deletar Registros.......................................................................121
8.1 Sobre INSERT........................................................................................................122
8.1.1 INSERT Múltiplo..............................................................................................123
8.2 Dollar Quoting.........................................................................................................125
8.3 UPDATE – Alterando Registros.............................................................................127
8.3.1 Atualizando Mais de Um Campo.....................................................................127
8.4 DELETE – Removendo Registros..........................................................................128
8.5 A Cláusula RETURNING........................................................................................129
8.5.1 RETURNING com INSERT.............................................................................129
8.5.2 RETURNING com UPDATE............................................................................129
8.5.3 RETURNING com DELETE............................................................................130
8.6 UPSERT – ON CONFLICT.....................................................................................131
8.6.1 Sobrescrevendo Registros com UPSERT......................................................132
9 Novas Tabelas a Partir de Dados..................................................................................135
9.1 Sobre Novas Tabelas a Partir de Dados................................................................136
9.2 SELECT INTO........................................................................................................137
9.3 CREATE TABLE AS...............................................................................................138
9.4 CREATE TABLE … (like …)...................................................................................139
10 Conjuntos.....................................................................................................................141
10.1 Sobre Conjuntos...................................................................................................142
10.2 União (UNION).....................................................................................................144
10.3 Intersecção (INTERSECT)...................................................................................145
10.4 Diferença (EXCEPT).............................................................................................146
11 Casamento de Padrões e Expressões Regulares.......................................................147
11.1 Sobre Casamento de Padrões e Expressões Regulares.....................................148
11.2 LIKE (~~) e ILIKE (∼∼*).......................................................................................149
11.3 SIMILAR TO.........................................................................................................152
11.4 Função substring com Três Parâmetros..............................................................154
11.5 Expressões Regulares POSIX.............................................................................155
12 Subconsultas................................................................................................................157
8
12.1 Sobre Subconsultas..............................................................................................158
12.1.1 Subconsulta no WHERE...............................................................................158
12.1.2 Subconsulta no SELECT...............................................................................159
12.1.3 Subconsulta no FROM..................................................................................159
12.1.4 EXISTS..........................................................................................................159
12.1.5 IN e NOT IN...................................................................................................160
12.1.6 ANY ou SOME...............................................................................................161
12.1.7 ALL................................................................................................................161
12.1.8 Comparação de Linha Única.........................................................................162
12.2 Subconsultas Laterais..........................................................................................163
12.3 Subconsultas em INSERT....................................................................................164
12.4 Subconsultas em UPDATE..................................................................................166
12.4.1 Atualizar Campo por Resultado de Consulta................................................166
12.4.2 Atualizar Campo Copiando o Restante da Linha..........................................166
12.4.3 Atualizar uma Tabela Através de Outra Tabela............................................167
12.5 Subconsultas em DELETE...................................................................................168
13 Junções (Joins)............................................................................................................170
13.1 Sobre Junções......................................................................................................171
13.2 CROSS JOIN (Junção Cruzada)..........................................................................172
13.3 NATURAL JOIN (Junção Natural)........................................................................173
13.4 INNER JOIN (Junção Interna)..............................................................................174
13.5 OUTER JOIN (Junção Externa)...........................................................................175
13.5.1 LEFT OUTER JOIN (Junção Externa à Esquerda).......................................175
13.5.2 RIGHT OUTER JOIN (Junção Externa à Direita).........................................176
13.5.3 FULL OUTER JOIN (Junção Externa Total).................................................177
13.6 SELF JOIN (Auto-Junção)....................................................................................178
14 Funções Built-ins..........................................................................................................180
14.1 Sobre Funções.....................................................................................................181
14.2 Funções Matemáticas..........................................................................................182
14.3 Funções de Data e Hora......................................................................................183
14.3.1 extract(...)......................................................................................................183
14.4 Funções de Strings...............................................................................................184
14.4.1 to_char()........................................................................................................185
14.5 Funções de Sistema.............................................................................................187
15 Agrupamentos de Dados.............................................................................................188
15.1 Sobre Agrupamentos de Dados...........................................................................189
15.2 Funções de Agregação (ou de Grupos de Dados)..............................................190
15.3 GROUP BY...........................................................................................................192
15.4 A Cláusula HAVING..............................................................................................193
15.5 A Cláusula FILTER...............................................................................................194
16 SEQUENCE – Sequência............................................................................................195
16.1 Sobre Sequência..................................................................................................196
16.2 Funções de Manipulação de Sequência..............................................................198
16.3 Usando Sequências em Tabelas..........................................................................199
16.4 Alterando uma Sequência....................................................................................201
16.5 Apagando uma Sequência...................................................................................202
16.6 TRUNCATE para Reiniciar Sequências de uma Tabela......................................203
17 VIEW – Visão...............................................................................................................206
17.1 Sobre Visão..........................................................................................................207
17.2 Visões Materializadas...........................................................................................210
9
18 Cursores.......................................................................................................................214
18.1 Sobre Cursores.....................................................................................................215
18.1.1 Parâmetros....................................................................................................215
18.2 FETCH – Recuperando Linhas de um Cursor.....................................................217
18.3 MOVE – Movendo Cursores.................................................................................219
18.4 CLOSE – Fechando Cursores..............................................................................220
18.5 Apagando e Atualizando a Linha Onde o Cursor Aponta....................................221
19 BLOB............................................................................................................................223
19.1 Sobre BLOB..........................................................................................................224
19.2 Removendo BLOBs..............................................................................................226
20 Bytea............................................................................................................................227
20.1 Sobre Bytea..........................................................................................................228
21 COPY...........................................................................................................................231
21.1 Sobre COPY.........................................................................................................232
21.2 Formato CSV........................................................................................................237
21.3 COPY Remoto......................................................................................................238
22 Range Types - Tipos de Intervalos..............................................................................240
22.1 Sobre Tipos de Intervalos.....................................................................................241
22.1.1 Simbologia de Limites de Intervalos.............................................................241
22.1.2 Built-in Range Types.....................................................................................241
22.1.3 Extração de Limites Superior e Inferior.........................................................243
22.1.4 Contenção: O Operador Contém @>...........................................................243
22.1.5 Contenção: O Operador Contido <@............................................................244
22.1.6 Overlaps - Sobreposições.............................................................................244
22.1.7 Intersecção....................................................................................................244
22.1.8 Intervalo Vazio...............................................................................................245
22.1.9 Sem Limites (Mínimo, Máximo e Ambos).....................................................246
22.1.10 Aplicação de Conceitos...............................................................................247
23 Tipos de Dados Criados por Usuários.........................................................................249
23.1 Sobre Tipos de Dados Criados por Usuários.......................................................250
23.1.1 Tipo Concha (Shell Type)..............................................................................251
23.2 Tipos Compostos (Composite Types)..................................................................252
23.3 Tipos Enumerados (Enumerated Types).............................................................254
23.4 Tipos por Faixa (Range Types)............................................................................255
23.5 Tipos Base (Base Types).....................................................................................256
24 DOMAIN (Domínio)......................................................................................................257
24.1 Sobre Domínio......................................................................................................258
24.2 DOMAIN vs TYPE................................................................................................259
25 SCHEMA (Esquema)...................................................................................................261
25.1 Sobre Esquemas..................................................................................................262
25.2 Caminho de Busca de Esquema - Schema Search Path....................................265
26 MVCC...........................................................................................................................266
26.1 Sobre MVCC.........................................................................................................267
26.2 Transação.............................................................................................................267
26.2.1 Utilidade de uma transação..........................................................................268
26.3 Fenômenos Indesejados em Transações............................................................268
26.4 Níveis de Isolamento............................................................................................269
26.5 O Conceito de ACID.............................................................................................270
26.6 Travas...................................................................................................................275
26.7 SAVEPOINT – Ponto de Salvamento..................................................................277
10
26.7.1 RELEASE SAVEPOINT................................................................................279
26.8 SELECT ... FOR UPDATE...................................................................................281
27 PREPARE....................................................................................................................282
27.1 Sobre PREPARE..................................................................................................283
28 PREPARE TRANSACTION.........................................................................................286
28.1 Sobre PREPARE TRANSACTION.......................................................................287
29 Arrays...........................................................................................................................290
29.1 Sobre Arrays.........................................................................................................291
29.2 Arrays PostgreSQL...............................................................................................292
29.3 Inserindo Valores de Array...................................................................................293
29.3.1 Implementando Limites em Arrays................................................................296
29.4 Consultas em Arrays............................................................................................300
29.4.1 Slicing – Fatiamento de Vetores...................................................................301
29.5 Modificando Arrays...............................................................................................303
29.6 Funções de Arrays................................................................................................304
29.7 Operadores de Arrays..........................................................................................306
29.8 Alterando Tipos para Array...................................................................................307
30 INDEX - Índice.............................................................................................................310
30.1 Sobre Índice..........................................................................................................311
30.1.1 Dicas Gerais..................................................................................................311
30.2 Métodos de Indexação.........................................................................................313
30.2.1 BTREE...........................................................................................................313
30.2.2 GIST..............................................................................................................313
30.2.3 GIN................................................................................................................313
30.2.4 HASH.............................................................................................................313
30.3 Índices Compostos...............................................................................................314
30.4 Índices Parciais.....................................................................................................315
30.5 Fillfactor - Fator de Preenchimento......................................................................317
30.6 Reconstrução de Índices – REINDEX..................................................................320
30.7 CLUSTER – Índices Clusterizados......................................................................322
30.8 Excluindo um Índice..............................................................................................324
30.8.1 Antes de Excluir um Índice............................................................................324
31 Modelos de Banco de Dados – Templates..................................................................325
31.1 Sobre Templates..................................................................................................326
32 Herança........................................................................................................................329
32.1 Sobre Herança de Tabelas...................................................................................330
33 Relacionamentos.........................................................................................................337
33.1 Cardinalidade........................................................................................................338
33.1.1 Simbologia.....................................................................................................339
33.1.2 Cardinalidade Mínima e Cardinalidade Máxima...........................................339
33.2 Relacionamento 1:1 - Um para Um......................................................................340
33.2.1 Relacionamento (0, 1):(0, 1).........................................................................340
33.2.2 Relacionamento (1, 1):(0, 1).........................................................................342
33.2.3 Relacionamento (0, 1):(1, 1).........................................................................344
33.2.4 Relacionamento (1, 1):(1, 1).........................................................................346
33.2.5 Cardinalidade 1:1 Como Estratégia de Particionamento..............................348
33.3 Relacionamento 1:n - Um para Muitos.................................................................349
33.3.1 Relacionamento (0, 1):(0, n).........................................................................349
33.3.2 Relacionamento (1, 1):(0, n).........................................................................351
33.4 Relacionamento n:n - Muitos para Muitos............................................................353
11
33.5 Relacionamento Ternário.....................................................................................355
12
A Apostila
• Sobre a Apostila
• Créditos de Softwares Utilizados
13
Sobre a Apostila
Para um melhor entendimento, esta apostila possui alguns padrões, tais como:
$ psql
São de três tipos, sendo que o sinal que precede o comando indica sua função,
que conforme ilustrados acima são respectivamente:
search mydomain.com
nameserver 10.0.0.200
nameserver 10.0.0.201
São demonstrações de como um arquivo deve ser alterado, como deve ser ou
partes do próprio.
14
Se tiver três pontos seguidos separados por espaços significa que há outros
conteúdos que ou não importam no momento ou que há uma continuação (a qual é
anunciada).
Aviso
Aviso:
Observação
Obs.:
15
Créditos de Softwares Utilizados
Software utilizados para elaboração desta obra.
Editor de Texto
LibreOffice Writer
www.libreoffice.org
INKSCAPE
Inkscape
www.inkscape.org
Editor de Imagens
GIMP
www.gimp.org
Sistema Operacional
16
Linux
www.linux.com
Distribuições
Ubuntu
www.ubuntu.com
Linux Mint
www.linuxmint.com
17
Apresentação
• Objetivo
• Cenário do Curso
• Sobre o PostgreSQL
18
Objetivo
Este curso visa capacitar seus alunos a utilizar a linguagem SQL, que é a
linguagem padrão para bancos de dados relacionais.
Serão vistas boas práticas de modelagem de banco de dados, a fim de construir
bases de dados bem estruturadas.
Cenário do Curso
Os exercícios desta apostila, em sua maioria, terão como base um banco de dados
de uma empresa fictícia, a “Chiquinho da Silva S. A.”.
Tal banco conta com alguns cadastros, cujo DER (Diagrama Entidade-
Relacionamento), pode ser conferido na figura da próxima página:
19
20
Sobre o PostgreSQL
O que é o PostgreSQL
• Consultas complexas;
• Chaves estrangeiras (foreign keys);
• Gatilhos (triggers);
• Visões (views);
• Integridade transacional.
O PostgreSQL pode também ser estendido pelo usuário para muitos propósitos,
por exemplo adicionando novos:
• Tipos de dados;
• Funções;
• Operadores;
• Funções agregadas;
• Métodos de indexação;
• Linguagens procedurais.
História do PostgreSQL
Dadas suas características poderosas e avançadas, como uma peça valiosa de
software se tornou livre e com seu código-fonte aberto? Assim como muitos outros
importantes projetos de código aberto, a resposta começa na Universidade da Califórnia,
em Berkeley (UCB).
O PostgreSQL, originalmente chamado Postgres, foi criado por um professor da
UCB do curso de Ciências da Computação chamado Michael Stonebraker, que passou a
ser o CTO da Informix Corporation. Stonebraker começou o Postgres em 1986 como um
projeto de continuação de seu antecessor, o Ingres, que agora pertence à Computer
21
Associates.
O nome Postgres é uma referência ao seu antecessor (algo como “após o Ingres”).
O Ingres foi desenvolvido em 1977 até 1985, que tinha sido um exercício de como
criar um sistema de banco de dados e de acordo com a clássica teoria de SGBDR
(Sistema Gerenciador de Banco de Dados Relacional).
O Postgres, desenvolvido entre 1986 a 1994, foi um projeto destinado a abrir novos
caminhos nos conceitos de banco de dados, tais como a exploração de tecnologias
“objeto-relacional”.
Stonebraker e seus estudantes de graduação desenvolveram o Postgres por oito
anos. Durante esse tempo, o Postgres introduziu rules, procedures, time travel, tipos
extensíveis com índices e conceitos objeto-relacionais.
O Postgres foi mais tarde comercializado para se tornar o Illustra que
posteriormente foi comprado pela Informix e integrado dentro de seu servidor universal.
A Informix foi adquirida pela IBM em 2001 por um bilhão de dólares.
Em 1995, dois estudantes Ph. D. do laboratório de Stonebraker, Andrew Yu e Jolly
Chen substituíram a linguagem de consulta Postgres’ POSTQUEL por um subconjunto
extendido de SQL. Eles renomearam o sistema para Postgres95. Em 1996, o Postgres95
se afastou da academia e iniciou uma nova vida, no mundo open source, quando um
grupo de desenvolvedores dedicados, fora de Berkeley, viu a promessa do sistema e se
dedicaram à continuação de seu desenvolvimento. Com grandes contribuições de tempo
e habilidade. Com trabalho e conhecimento técnico, esse grupo global de
desenvolvimento transformou o Postgres radicalmente. Durante os próximos oito anos,
eles trouxeram consistência e uniformidade para a base do código, criaram testes
detalhados de regressão para garantia de qualidade, criaram listas de discussão para
relatórios de bugs, consertaram vários bugs, adicionaram incríveis novos recursos, e
arredondaram o sistema preenchendo várias lacunas como documentação para
desenvolvedores e usuários. Os frutos desse trabalho foi um novo banco de dados que
ganhou uma reputação para a estabilidade de uma rocha sólida. Com o início dessa nova
vida no mundo open source, com muitos novos recursos e melhorias, o sistema de banco
de dados teve seu nome atual: PostgreSQL, (“Postgres” ainda é usado como um apelido
de fácil pronúncia).
O PostgreSQL começou na versão 6.0, dando crédito a seus muitos anos
anteriores de desenvolvimento. Com a ajuda de centenas de desenvolvedores ao redor
do mundo, o sistema foi alterado e melhorado em quase todas as áreas. Nos próximos
quatro anos (versões de 6.0 a 7.0), grandes melhorias e novos recursos foram feitos
como:
22
• Melhoramentos em Tipos Embutidos (built-in)
Novos tipos nativos foram adicionados incluindo uma ampla gama de tipos de
data/tempo e tipos geométricos adicionais.
• Velocidade
Os quatro anos seguintes (versões de 7.0 a 7.4) trouxe o Write-Ahead Log (WAL),
esquemas (schemas) SQL, consultas preparadas, OUTER JOINS, consultas complexas,
sintaxe SQL92 JOIN, TOAST, suporte a IPv6, padrão SQL de informações de esquema,
indexação full-text, auto-vacuum, linguagens procedurais Perl/Python/TCL, suporte
melhorado a SSL, uma revisão de otimizador, informações de estatísticas de banco de
dados, segurança adicionada, funções de tabela, melhoramentos de log, significantes
aumentos de velocidade entre outras coisas. Uma pequena medida de desenvolvimento
intensivo do PostgreSQL se reflete nas notas de lançamento. Hoje, a base de usuários do
PostgreSQL é maior do que nunca e inclui um considerável grupo de grandes
corporações que o usam em ambientes exigentes. Algumas dessas empresas como
Afilias e Fujitsu tem feito contribuições significantes ao desenvolvimento do PostgreSQL.
E, fiel às suas raízes, ele continua a melhorar em sofisticação e performance, agora mais
do que nunca.
A versão 8.0 do PostgreSQL foi a mais aguardada no mercado de bancos de
dados corporativos, trazendo novos recursos como tablespaces, stored procedures Java,
Point
In Time Recovery (PITR), e transações aninhadas (savepoints). Junto com o lançamento
dessa versão veio a característica mais aguardada; uma versão nativa para Windows.
Muitas organizações, agências governamentais e empresas usam o PostgreSQL.
São encontradas instalações em organizações como ADP, Cisco, NTT Data,
NOAA, Research In Motion, Serviço Florestal dos EUA e a Sociedade Química
Americana. hoje, é raro encontrar uma grande corporação ou agência de governo que não
usa o PostgreSQL em pelo menos um departamento. Se teve um tempo para considerar
seriamente utilizar o PostgreSQL para agilizar sua aplicação ou negócio, que seja
agora! ;)
23
Limites do PostgreSQL
Limite Valor
Tamanho máximo de um banco de dados Ilimitado
Tamanho máximo de uma tabela 32 TB
Tamanho máximo de uma linha (registro) 1.6 TB
Tamanho máximo de um campo (coluna) 1 GB
Número máximo de linhas por tabela Ilimitado
Número máximo de colunas por tabela 250 - 1600 dependendo do tipo de coluna
Número máximo de índices por tabela Ilimitado
Suporte ao PostgreSQL
https://www.postgresql.org/support/
24
Suporte da Comunidade
• Sites Oifciais:
◦ Global: https://www.postgresql.org/
◦ Wiki: https://wiki.postgresql.org/
◦ Brasileiro: https://www.postgresql.org.br/
• Documentação:
• Listas de Discussão:
◦ Internacional: https://lists.postgresql.org
◦ Brasileira: https://listas.postgresql.org.br/
• Blogs
São vários os blogs ao redor do planeta sobre PostgreSQL, mas para facilitar
temos blogs oficiais da comunidade que aglutinam posts de outros blogs, de forma
a termos um conhecimento diversificado através de tutoriais e artigos divulgados
nesses.
• Outros:
Suporte Comercial
[1] https://www.postgresql.org/support/professional_support/
[2] https://www.postgresql.org/support/professional_hosting/
25
Derivações do PostgreSQL
[1] https://wiki.postgresql.org/wiki/PostgreSQL_derived_databases
Citus / CitusDB
Citus Data
https://www.citusdata.com/
Licença: AGPL 3.0
Descrição:
Postgres-XL
PGXLDG
http://www.postgres-xl.org/
Licença: BSD
Descrição:
Projetado para ambientes BI e de análise Big Data, tem capacidade MPP (Massively
Parallel Processing: Processamento Paralelo em Massa) e com recurso de shardig que
distribui os dados através de seus nós.
26
Greenplum Database
Greenplum
http://greenplum.org/
Licensa: Apache 2
Descrição:
Netezza
IBM
https://www.ibm.com/software/data/netezza/
Licença: Proprietária
Descrição:
Appliance baseada no motor do PostgreSQL, voltada para BI, análise preditiva e data
warehousing.
27
Vertica
HP
www.vertica.com
Licença: Proprietária
Descrição:
SGBD SQL analítico para demandas Big Data e BI de alta performance e escalabilidade.
Descrição:
28
PostgreSQL
–
SQL Básico
29
1 SQL
• O que é SQL
• Subdivisões SQL
• Identificadores
• Operadores
• Comentários SQL
30
1.1 O que é SQL
Structured Query Language – Linguagem Estruturada de Consulta, é a
linguagem usada nos SGBDs1 por padrão, no entanto cada um tem suas particularidades
dentro da própria linguagem, tendo implementações diferentes.
O mesmo objetivo pode ser feito de formas SQL diferentes de um SGBD pra outro.
Assim como em linguagens de programação “comuns”, existem palavras
reservadas, as quais não podem ser usadas como identificadores.
Cada comando SQL é finalizado com ponto e vírgula (;).
1 Originalmente da sigla em inglês DBMS (Data Base Management System): Sistema Gerenciador de Banco de Dados; que é
um conjunto de aplicativos, cuja função é gerenciar uma base dados. Exemplos: PostgreSQL, Oracle, DB2, MySQL, Firebird SQL, MS
SQL Server, Sybase, etc.
31
1.2 Subdivisões SQL
A linguagem SQL tem algumas divisões, que facilitam o entendimento da mesma,
categorizando seus comandos. Sendo que as mais conhecidas, que serão explicadas a
seguir, são: DDL, DML e DCL.
1.2.1 DDL
Data Definition Language – Linguagem de Definição de Dados, é a parte da
Linguagem SQL que trata, como o próprio nome diz, da definição da estrutura dos dados,
cujos efeitos se dão sobre objetos. Criação de bancos de dados, tabelas, views, triggers,
etc...
1.2.2 DML
Data Manipulation Language – Linguagem de Manipulação de Dados, é a parte
da Linguagem SQL que não altera a estrutura e sim os registros de uma base de dados,
cujos efeitos se dão sobre registros. São comandos que fazem consultas, inserem,
alteram ou apagam registros.
1.2.3 DCL
Data Control Language – Linguagem de Controle de Dados, é a parte da
linguagem SQL referente ao controle de acesso a objetos por usuários e seus respectivos
privilégios.
Os principais comandos SQL são:
32
1.3 Identificadores
Para nomearmos identificadores devemos usar como primeiro caractere letras ou
“_” (underline).
Apagando um objeto:
> DROP DATABASE abc;
Há uma maneira de fazer com que os identificadores criados sejam “case sensitive”, para
isso devemos criar os nomes de identificadores entre aspas dupas (“ ”). Inclusive, pode-se
até criar identificadores iniciando com caracteres numéricos (o que não é uma boa
prática):
> CREATE DATABASE "Abc";
33
Listando as bases de dados existentes via meta comando psql:
> \l
datname
-----------
template1
template0
postgres
Abc
123tEste
Obs.:
Como dito anteriormente, para manipular objetos com nomes fora do padrão, seu
identificador deve estar entre aspas:
> DROP DATABASE "Abc";
34
1.4 Operadores
Operador de multiplicação:
> SELECT 3 * 5;
?column?
----------
15
Divisão inteira:
> SELECT 7 / 2;
?column?
----------
3
?column?
--------------------
3.5000000000000000
35
Divisão com ponto flutuante com conversão de dado do divisor:
> SELECT 7 / 2::float4;
?column?
----------
3.5
?column?
----------
t
?column?
----------
t
36
1.5 Comentários SQL
ou
Os comentários de uma única linha são feitos com -- e de múltiplas linhas são
delimitados entre /* e */.
37
2 Tipos de Dados
• Sobre Tipos de Dados
• Tipos de Dados Numéricos
• Tipos de Dados de Data e Hora
• Tipos de Dados para Texto
• Nulo (Null)
• Booleano
• Tipos de Dados de Rede
• Outros Tipos
• Type Casts: Conversão de Tipos
38
2.1 Sobre Tipos de Dados
pg_typeof
-----------
integer
pg_typeof
-----------
unknown
Retorno dado como desconhecido por não saber exatamente que tipo de dado é a
string do parâmetro.
39
Descobrir que tipo de dado é '7' já convertendo (type cast) para char:
> SELECT pg_typeof('7'::char);
pg_typeof
-----------
character
pg_typeof
--------------------------
timestamp with time zone
pg_typeof
-----------
unknown
Outro caso que não há como determinar o tipo de dado. É preciso explicitar o tipo.
pg_typeof
-----------
date
pg_typeof
-----------
numeric
pg_typeof
-----------
bigint
40
Testando um valor booleano:
> SELECT pg_typeof(true);
pg_typeof
-----------
boolean
pg_typeof
-----------
regtype
41
2.2 Tipos de Dados Numéricos
Obs.:
Os tipos seriais são pseudo-tipos. São tipos inteiros na verdade, serial2 → int2,
serial4 → int4, serial8 → int8.
Quando um tipo serial é definido para um campo, seu valor é um inteiro cujo valor
padrão é o próximo número de um objeto sequência.
Aviso:
Para valores monetários utilize o tipo numeric. Não utilize money, pois o mesmo é
sensível à configuração lc_monetary e em uma eventual restauração, se o valor dessa
configuração for diferente do original pode haver distorção de valores, enquanto numeric
é mais “universal”.
42
Qual o tamanho (em bytes) de um valor para um número do tipo int2?:
> SELECT pg_column_size(1::smallint);
pg_column_size
----------------
2
pg_column_size
----------------
4
pg_column_size
----------------
8
pg_column_size
----------------
8
pg_column_size
----------------
4
?column?
----------
7
43
Cálculo com alias:
> SELECT 5 + 2 AS resultado;
resultado
-----------
7
Nome Descrição
9 Valor com o número especificado de dígitos
0 Valor com zeros à esquerda
. (ponto) Valor com o número especificado de dígitos
, (vírgula) Valor com o número especificado de dígitos
PR Valor negativo entre < e >
S Sinal preso ao número (utiliza o idioma)
L Símbolo da moeda (utiliza o idioma)
D Ponto decimal (utiliza o idioma)
G Separador de grupo (utiliza o idioma)
MI Sinal de menos na posição especificada (se número < 0)
PL Sinal de mais na posição especificada (se número > 0)
SG Sinal de mais/menos na posição especificada
RN [a] Algarismos romanos (entrada entre 1 e 3999)
TH ou th Sufixo de número ordinal
V Desloca o número especificado de dígitos (veja as notas sobre utilização)
EEEE Notação científica (ainda não implementada)
to_char
-----------------
MMIX
to_char
----------
1st
44
Número 3 ordinal (padrão inglês):
> SELECT to_char(3, '99999th');
to_char
----------
3rd
to_char
-----------------
3.148,50
to_char
-----------------
3,148.50
to_char
---------
00021
to_char to_char
--------- ---------
3- +3
45
2.3 Tipos de Dados de Data e Hora
Alguns tipos de data e hora aceitam um valor com uma precisão “p” que especifica
a quantidade de dígitos fracionais retidos no campo de segundos. Por exemplo: Se um
campo for especificado como do tipo interval(4), se no mesmo for inserido um
registro com valor “00:00:33.23439”, o mesmo terá seu valor arredondado para
“00:00:33.2344”, devido à customização da precisão para 4 dígitos. A faixa de precisão
aceita é de 0 a 6.
now
-------------------------------
2016-03-02 12:46:22.697306-03
now
------------
2015-06-25
now
-----------------
12:54:10.882728
Type cast do retorno da função now() extraindo a hora sem dígitos fracionais:
> SELECT now()::time(0) without time zone;
now
----------
12:59:17
46
Type cast do retorno da função now() extraindo a hora sem dígitos fracionais com
timezone (fuso horário):
> SELECT now()::time(0) with time zone;
now
-------------
12:59:25-03
?column?
-------------------------------
2015-07-02 13:00:26.391693-03
date
------------
2015-07-02
date
------------
2015-07-02
time
----------
08:00:00
?column?
----------
15:00:00
47
Type cast da string para data:
> SELECT '2015-12-31'::date;
date
------------
2015-12-31
A partir da função now() exibir a data no formato brasileiro e o nome do dia da semana
(em inglês):
> SELECT to_char(now(), 'DD/MM/YYYY DAY');
to_char
----------------------
25/06/2015 THURSDAY
48
2.4 Tipos de Dados para Texto
Também conhecidas como “strings” e seus valores são expressos entre apóstrofos.
?column?
----------
foo
?column?
----------
foobar
?column?
--------------------
Chiquinho da Silva
?column?
------------------------
Linha1\nLinha2\nLinha3
49
String com caracteres especias interpretados:
> SELECT E'Linha1\nLinha2\nLinha3';
?column?
----------
Linha1 +
Linha2 +
Linha3
?column?
-------------
Copo d'água
?column?
-------------
Copo d'água
?column?
----------------
Linha1+
Linha2 +
Linha3
50
2.5 Nulo (Null)
Um valor nulo é simplesmente um valor não preenchido, o que não deve ser
confundido com espaço.
?column?
----------
f
?column?
----------
t
?column?
----------
t
?column?
----------
t
51
2.6 Booleano
?column? ?column?
---------- ----------
f t
?column? ?column?
---------- ----------
t f
?column?
----------
t
?column?
----------
t
52
2.7 Tipos de Dados de Rede
Nome Descrição
cidr Endereços de redes IPv4 ou IPv6
inet Endereços de hosts ou redes IPv4 ou IPv6
macaddr MAC address (endreço físico)
pg_column_size
----------------
40
pg_column_size
----------------
22
pg_column_size
----------------
22
pg_column_size
----------------
10
53
Endereço de rede IPv4 inválido:
> SELECT '192.168.0.0/33'::cidr;
pg_column_size
----------------
36
pg_column_size
----------------
22
pg_column_size
----------------
19
pg_column_size
----------------
10
54
Endereço MAC como string:
> SELECT pg_column_size('00:00:00:00:00:00'::text);
pg_column_size
----------------
21
pg_column_size
----------------
6
55
2.8 Outros Tipos
Obs.:
O “+” (mais) nos comandos do psql, dá mais informações quando inserido ao final
de um comando.
http://www.postgresql.org/docs/current/static/datatype.html
56
2.9 Type Casts: Conversão de Tipos
ou
Sintaxe PostgreSQL
expressão::tipo
Resultado
-----------
77
Tudo o que é envolvido por apóstrofos (') é considerado como uma string.
O operador duplo pipe (||) concatena de strings. No exemplo resulta na string '70'.
Se caracteres numéricos não estiverem envolvidos por apóstrofos são
considerados como números.
As strings foram convertidas e então com o operador (+) foram somadas.
Resultado
-----------
77
57
3 Interfaces
• Sobre Interfaces de Acesso a um Banco de Dados
• psql
• pgAdmin 3
• phpPgAdmin
58
3.1 Sobre Interfaces de Acesso a um Banco de Dados
Um SGBD não seria tão útil se não tivéssemos como acessar os dados que ele
guarda. Para isso precisamos de uma interface para interagir.
Uma interface pode ser um cliente modo texto, um aplicativo desktop ou uma
interface web.
Um sistema que uma pessoa utiliza para se fazer um cadastro ou consultas
também é uma interface.
59
3.2 psql
Sintaxe de Uso:
O comando acima fez com que tentasse uma conexão com o usuário postgres, no
host 172.158.50.1 na base de dados postgres.
?column?
----------
7
(1 row)
data_directory
------------------------------
/home/28532757871/pgsql/data
test
------
foo
60
Passando comandos via pipe:
$ echo "SELECT 5 + 2; SELECT 'foo';" | psql
?column?
----------
7
?column?
----------
foo
O psql possui comandos próprios, inerentes ao aplicativo em si, que não são SQL.
Para consultar essa ajuda do psql, dê o seguinte comando dentro de sua interface:
> \?
Podemos também pedir uma ajuda ao psql sobre comandos SQL. Essa ajuda é
feita com o comando \help [comando_SQL] ou \h [comando_SQL].
Por exemplo, para nos conectarmos à base template1, dentro do psql fazemos:
> \c template1
61
Por exemplo, para nos conectarmos à base template1, dentro do psql fazemos:
current_database
------------------
template1
3.2.4 ~/.psqlrc
O arquivo .psqlrc, que fica no diretório do usuário é um nome de arquivo padrão
que, se existir, o psql o lê e executa seu conteúdo.
O conteúdo do psqlrc pode ser tanto meta comandos do psql ou comandos SQL.
É muito útil para fazer alguns ajustes.
Comandos passados:
62
3.3 pgAdmin 3
Para quem prefere uma interface gráfica para interagir com o SGBD, se tratando
de PostgreSQL, uma das alternativas mais conhecidas é o pgAdmin 3, cujo site oficial é
http://www.pgadmin.org/.
63
3.4 phpPgAdmin
64
4 Objetos de Bancos de Dados
• Sobre Objetos de Bancos de Dados
• Descrição (Comentário) de Objetos
65
4.1 Sobre Objetos de Bancos de Dados
List of databases
Name | Owner | Encoding | Collate | Ctype | Access privileges
------------+----------+----------+-------------+-------------+-----------------------
db_empresa | postgres | UTF8 | en_US.UTF-8 | en_US.UTF-8 |
db_teste | postgres | UTF8 | en_US.UTF-8 | en_US.UTF-8 |
postgres | postgres | UTF8 | en_US.UTF-8 | en_US.UTF-8 |
template0 | postgres | UTF8 | en_US.UTF-8 | en_US.UTF-8 | =c/postgres +
| | | | | postgres=CTc/postgres
template1 | postgres | UTF8 | en_US.UTF-8 | en_US.UTF-8 | =c/postgres +
| | | | | postgres=CTc/postgres
datname
------------
template1
template0
postgres
db_empresa
db_teste
Acessando a base:
> \c db_teste
66
Criação de uma tabela sem campos dentro da base db_teste:
> CREATE TABLE tb_teste();
List of relations
Schema | Name | Type | Owner
--------+----------+-------+----------
public | tb_teste | table | postgres
tablename
-----------
tb_teste
Table "public.tb_teste"
Column | Type | Modifiers
--------+------+-----------
> \d tb_teste
Table "public.tb_teste"
Column | Type | Modifiers
--------+---------+-----------
campo | integer |
67
Renomeando a tabela:
> ALTER TABLE tb_teste RENAME TO tb_1;
Listando sequências:
> \ds
List of relations
Schema | Name | Type | Owner
--------+------+----------+----------
public | sq_1 | sequence | postgres
relname
---------
sq_1
Table "public.tb_1"
Column | Type | Modifiers
--------+---------+-----------------------------------
campo | integer | default nextval('sq_1'::regclass)
68
Tentativa de remoção da sequência sq_1, que está atrelada ao valor padrão de campo da
tabela tb_1:
> DROP SEQUENCE sq_1;
A mensagem diz que a remoção da sequência foi feita, mas como consequência,
devido à dependência do campo da tabela tb_1, a restrição DEFAULT foi apagada.
Exibindo a estrutura da tabela tb_1 após apagar a sequência que ela dependia:
> \d tb_1
Table "public.tb_1"
Column | Type | Modifiers
--------+---------+-----------
campo | integer |
Inserir um dado:
> INSERT INTO tb_cpf (cpf) VALUES ('12345678901');
69
Tentativa de alteração de tipo:
> ALTER TABLE tb_cpf ALTER cpf TYPE bigint;
Foi exibida uma mensagem de erro, pois nesse caso é necessário fazer um cast
com a cláusula USING.
70
4.2 Descrição (Comentário) de Objetos
List of relations
Schema | Name | Type | Owner
--------+------------------+----------+----------
public | tb_1 | table | postgres
public | tb_bairro | table | postgres
public | tb_bairro_id_seq | sequence | postgres
List of relations
Schema | Name | Type | Owner
--------+-----------+-------+----------
public | tb_1 | table | postgres
public | tb_bairro | table | postgres
List of relations
Schema | Name | Type | Owner | Size | Description
--------+-----------+-------+----------+------------+-------------
public | tb_1 | table | postgres | 0 bytes |
public | tb_bairro | table | postgres | 8192 bytes |
71
Inserindo um comentário (descrição) na tabela tb_bairro:
> COMMENT ON TABLE tb_bairro IS 'Tabela de bairros';
List of relations
Schema | Name | Type | Owner | Size | Description
--------+-----------+-------+----------+------------+-------------------
public | tb_1 | table | postgres | 0 bytes |
public | tb_bairro | table | postgres | 8192 bytes | Tabela de bairros
List of relations
Schema | Name | Type | Owner | Size | Description
--------+-----------+-------+----------+------------+-------------
public | tb_bairro | table | postgres | 8192 bytes |
72
5 Tabelas
• Sobre Tabelas
• Tabelas Temporárias
• UNLOGGED TABLE – Tabela Não Logada
• Fillfactor de Tabela
73
5.1 Sobre Tabelas
. . .
74
Exibir estrutura da tabela após alteração feita:
> \d tb_colaborador
Table "public.tb_colaborador"
Column | Type | Modifiers
--------------+-----------------------+------------------------------------------------------
id | integer | not null default nextval('sq_colaborador'::regclass)
cpf | character varying(11) |
setor | integer |
cargo | integer |
chefe_direto | integer |
salario | numeric(9,2) |
dt_admis | date | default now()
dt_demis | date |
ativo | boolean | default true
Indexes:
"pk_colaborador" PRIMARY KEY, btree (id)
Foreign-key constraints:
"fk_cargo_colaborador" FOREIGN KEY (cargo) REFERENCES tb_cargo(id) ON UPDATE CASCADE ON DELETE
CASCADE
"fk_colaborador_colaborador" FOREIGN KEY (chefe_direto) REFERENCES tb_colaborador(id)
"fk_pf_colaborador" FOREIGN KEY (cpf) REFERENCES tb_pf(cpf) ON UPDATE CASCADE ON DELETE CASCADE
"fk_setor_colaborador" FOREIGN KEY (setor) REFERENCES tb_setor(id) ON UPDATE CASCADE ON DELETE
CASCADE
Referenced by:
TABLE "tb_colaborador" CONSTRAINT "fk_colaborador_colaborador" FOREIGN KEY (chefe_direto)
REFERENCES tb_colaborador(id)
> \d tb_colaborador
Table "public.tb_colaborador"
Column | Type | Modifiers
--------------+-----------------------+------------------------------------------------------
id | integer | not null default nextval('sq_colaborador'::regclass)
cpf | character varying(11) |
setor | integer |
cargo | integer |
chefe_direto | integer |
salario | numeric(9,2) |
dt_admis | date | default now()
dt_demis | date |
ativo | boolean | default true
nova_coluna | smallint |
Indexes:
"pk_colaborador" PRIMARY KEY, btree (id)
Foreign-key constraints:
"fk_cargo_colaborador" FOREIGN KEY (cargo) REFERENCES tb_cargo(id) ON UPDATE CASCADE ON DELETE CASCADE
"fk_colaborador_colaborador" FOREIGN KEY (chefe_direto) REFERENCES tb_colaborador(id)
"fk_pf_colaborador" FOREIGN KEY (cpf) REFERENCES tb_pf(cpf) ON UPDATE CASCADE ON DELETE CASCADE
"fk_setor_colaborador" FOREIGN KEY (setor) REFERENCES tb_setor(id) ON UPDATE CASCADE ON DELETE CASCADE
Referenced by:
TABLE "tb_colaborador" CONSTRAINT "fk_colaborador_colaborador" FOREIGN KEY (chefe_direto) REFERENCES
tb_colaborador(id)
75
Exibir estrutura da tabela após alteração feita:
> \d tb_colaborador
Table "public.tb_colaborador"
Column | Type | Modifiers
--------------+-----------------------+------------------------------------------------------
id | integer | not null default nextval('sq_colaborador'::regclass)
cpf | character varying(11) |
setor | integer |
cargo | integer |
chefe_direto | integer |
salario | numeric(9,2) |
dt_admis | date | default now()
dt_demis | date |
ativo | boolean | default true
nova_coluna | numeric(7,2) |
Indexes:
"pk_colaborador" PRIMARY KEY, btree (id)
Foreign-key constraints:
"fk_cargo_colaborador" FOREIGN KEY (cargo) REFERENCES tb_cargo(id) ON UPDATE CASCADE ON DELETE CASCADE
"fk_colaborador_colaborador" FOREIGN KEY (chefe_direto) REFERENCES tb_colaborador(id)
"fk_pf_colaborador" FOREIGN KEY (cpf) REFERENCES tb_pf(cpf) ON UPDATE CASCADE ON DELETE CASCADE
"fk_setor_colaborador" FOREIGN KEY (setor) REFERENCES tb_setor(id) ON UPDATE CASCADE ON DELETE CASCADE
Referenced by:
TABLE "tb_colaborador" CONSTRAINT "fk_colaborador_colaborador" FOREIGN KEY (chefe_direto) REFERENCES
tb_colaborador(id)
Table "public.tb_colaborador"
Column | Type | Modifiers
---------------+-----------------------+------------------------------------------------------
id | integer | not null default nextval('sq_colaborador'::regclass)
cpf | character varying(11) |
setor | integer |
cargo | integer |
chefe_direto | integer |
salario | numeric(9,2) |
dt_admis | date | default now()
dt_demis | date |
ativo | boolean | default true
ultima_coluna | numeric(7,2) |
Indexes:
"pk_colaborador" PRIMARY KEY, btree (id)
Foreign-key constraints:
"fk_cargo_colaborador" FOREIGN KEY (cargo) REFERENCES tb_cargo(id) ON UPDATE CASCADE ON DELETE CASCADE
"fk_colaborador_colaborador" FOREIGN KEY (chefe_direto) REFERENCES tb_colaborador(id)
"fk_pf_colaborador" FOREIGN KEY (cpf) REFERENCES tb_pf(cpf) ON UPDATE CASCADE ON DELETE CASCADE
"fk_setor_colaborador" FOREIGN KEY (setor) REFERENCES tb_setor(id) ON UPDATE CASCADE ON DELETE CASCADE
Referenced by:
TABLE "tb_colaborador" CONSTRAINT "fk_colaborador_colaborador" FOREIGN KEY (chefe_direto) REFERENCES
tb_colaborador(id)
76
Exibir estrutura da tabela após alteração feita:
> \d tb_colaborador
Table "public.tb_colaborador"
Column | Type | Modifiers
--------------+-----------------------+------------------------------------------------------
id | integer | not null default nextval('sq_colaborador'::regclass)
cpf | character varying(11) |
setor | integer |
cargo | integer |
chefe_direto | integer |
salario | numeric(9,2) |
dt_admis | date | default now()
dt_demis | date |
ativo | boolean | default true
Indexes:
"pk_colaborador" PRIMARY KEY, btree (id)
Foreign-key constraints:
"fk_cargo_colaborador" FOREIGN KEY (cargo) REFERENCES tb_cargo(id) ON UPDATE CASCADE ON DELETE CASCADE
"fk_colaborador_colaborador" FOREIGN KEY (chefe_direto) REFERENCES tb_colaborador(id)
"fk_pf_colaborador" FOREIGN KEY (cpf) REFERENCES tb_pf(cpf) ON UPDATE CASCADE ON DELETE CASCADE
"fk_setor_colaborador" FOREIGN KEY (setor) REFERENCES tb_setor(id) ON UPDATE CASCADE ON DELETE CASCADE
Referenced by:
TABLE "tb_colaborador" CONSTRAINT "fk_colaborador_colaborador" FOREIGN KEY (chefe_direto) REFERENCES
tb_colaborador(id)
Renomeando a tabela:
> ALTER TABLE tb_foo RENAME TO tb_foo_bar;
O comando “DROP”, como já foi mencionado, serve pra eliminar objetos, tais como
uma tabela.
77
Criação da tabela de cidades, que depende da tabela de estados:
> CREATE TEMP TABLE tb_cidade(
id serial PRIMARY KEY,
nome text,
uf char(2),
CONSTRAINT fk_uf_cidade_uf FOREIGN KEY (uf) REFERENCES tb_uf (uf));
Tentativa de apagar tb_uf que tem tb_cidade como sua dependente por relacionamento:
> DROP TABLE tb_uf;
Descrição de tb_uf que entre outras informações diz que é referenciada por tb_cidade:
> \d tb_uf
Table "pg_temp_2.tb_uf"
Column | Type | Modifiers
--------+--------------+-----------
uf | character(2) | not null
nome | text |
Indexes:
"tb_uf_pkey" PRIMARY KEY, btree (uf)
Referenced by:
TABLE "tb_cidade" CONSTRAINT "fk_uf_cidade_uf" FOREIGN KEY (uf) REFERENCES tb_uf(uf)
78
Descrição de tb_cidade que exibe também que ela referencia tb_uf através de uma chave
estrangeira:
> \d tb_cidade
Table "pg_temp_2.tb_cidade"
Column | Type | Modifiers
--------+--------------+--------------------------------------------------------
id | integer | not null default nextval('tb_cidade_id_seq'::regclass)
nome | text |
uf | character(2) |
Indexes:
"tb_cidade_pkey" PRIMARY KEY, btree (id)
Foreign-key constraints:
"fk_uf_cidade_uf" FOREIGN KEY (uf) REFERENCES tb_uf(uf)
O comando TRUNCATE apaga todos os registros de uma tabela, portanto, deve ser
usado com cautela.
Apesar de apagar todos os dados de uma tabela é um comando de definição e não
de manipulação, ou seja, é um comando DDL.
Sintaxe:
79
Redefinindo a Tabela "tb_pf80" Como Vazia:
> TRUNCATE tb_pf80;
Aviso:
Para usarmos o TRUNCATE em tabelas que outros objetos são dependentes, temos
que fazer isso em cascata (CASCADE).
IF NOT EXISTS é uma cláusula interessante para criação de objetos, sendo eles;
TABLE (tabela), FOREIGN TABLE (tabela estrangeira) e EXTENSION (extensão).
Sua função é fazer com que se o objeto de mesmo nome já existir ele apenas
retorna um informe em vez de um erro.
Sintaxe:
80
5.2 Tabelas Temporárias
São tabelas que só podem ser acessadas diretamente pelo usuário que a criou e
na sessão corrente. Assim que o usuário criador da mesma se desconectar da sessão em
que ela foi criada, a tabela temporária deixará de existir.
A sintaxe de criação é igual à de uma tabela normal, apenas acrescenta-se a
palavra “TEMPORARY” ou “TEMP” após CREATE.
81
5.3 UNLOGGED TABLE – Tabela Não Logada
Uma tabela “unlogged” é uma tabela em que os dados não são escritos para o
WAL (Write-Ahead Log: logs de transação), que faz com que fique consideravelmente
mais rápida do que uma tabela comum. Porém, não são seguras contra falhas (crash):
uma tabela unlogged é automaticamente truncada após uma falha ou um desligamento
inapropriado.
O conteúdo de uma tabela UNLOGGED não é replicado para servidores standby.
Qualquer índice criado em uma tabela desse tipo é automaticamente também
“unlogged”, porém índices GiST atualmente não são suportados e não podem ser criados
em uma tabela unlogged.
É um tipo de tabela rápida, mas insegura. Não deve ser utilizada para operações
que precisem de persistência de dados.
Tabelas não logadas são muito úteis onde não é importante a durabilidade dos
dados. Por exemplo: cache de dados, informações temporárias acessíveis a todas
sessões abertas, cargas ETL e etc.
Time: 1922,384 ms
Time: 3806,184 ms
82
Sair do psql:
> \q
ou
<Ctrl> + D
Entrar no psql:
$ psql
campo
-------
1
2
3
4
5
Sair do psql:
> \q
ou
<Ctrl> + D
83
Iniciar o serviço do PostgreSQL:
$ pg_ctl start
Entrar no psql:
$ psql
campo
-------
No catálogo pg_class, utilizando de expressão regular que case com os nomes das
tabelas criadas, verificar o tipo de persistência:
> SELECT
oid, relfilenode, relname, relpersistence, relkind
FROM pg_class
WHERE relname ~ '^tb_.*logged';
Uma tabela comum a persistência é um "p", enquanto que uma tabela não logada é
representada por um "u". Ou seja, se relpersistence for "u" é unlogged.
84
Mudar tabela logada para não logada:
> ALTER TABLE tb_teste_logged SET UNLOGGED;
Quando uma tabela muda seu tipo de persistência de dados, ela tem que ser
totalmente reescrita, sendo necessário criar um novo arquivo. Isso explica a mudança de
relfilenode após alterar as tabelas.
85
5.4 Fillfactor de Tabela
Fillfactor para uma tabela é uma porcentagem entre 10 e 100 (sendo que 100
é o padrão). Quando um valor menor é definido, operações de INSERT faz o
preenchimento das páginas até o valor indicado, o espaço restante é reservado para
operações de UPDATE. Isso dá uma chance para uma cópia de uma linha modificada ser
alocada na mesma página que a linha original, que é mais eficiente do que alocar em uma
página diferente.
Para uma tabela cujas entradas nunca são modificadas (tabela estática),
empacotamento completo (fillfactor = 100) é a melhor escolha, mas para tabelas
cujos dados são modificados intensamente, valores menores para fillfactor é mais
apropriado. Esse parâmetro não pode ser ajustado para tabelas TOAST.
Média: 1793,763 ms
pg_size_pretty
----------------
10 MB
Time: 2182,260 ms
86
Tamanho da tabela após o UPDATE:
> SELECT pg_size_pretty(pg_relation_size('tb_ff100'));
pg_size_pretty
----------------
21 MB
Média: 2152,716 ms
pg_size_pretty
----------------
21 MB
Time: 815,024 ms
pg_size_pretty
----------------
21 MB
87
6 Restrições (Constraints)
• Sobre Restrições
• Valor padrão (DEFAULT)
• CHECK
• NOT NULL
• UNIQUE
• A Cláusula [NOT] DEFERRABLE
• Chave Primária / Primary Key
• Chave Estrangeira / Foreign Key
88
6.1 Sobre Restrições (Constraints)
São regras que inserimos para que uma coluna não receba dados indesejados.
São regras para manter a base de dados consistente de acordo com regras de
negócio.
89
6.2 Valor Padrão (DEFAULT)
O exemplo de criação de tabela acima, mostra o campo “uf ”, o qual se não for
inserido algum valor, o sistema, por padrão o preencherá com o valor “SP”.
Para testarmos, vamos fazer algumas inserções.
nome | uf
-------------+----
Guarulhos | SP
Santo André | SP
Mauá | SP
João Pessoa | PB
90
6.3 CHECK
Especifica que valores são permitidos em uma determinada coluna.
No exemplo evita que o campo preco tenha um valor inserido que não seja menor
do que zero.
ERROR: new row for relation "tb_check" violates check constraint "tb_check_preco_check"
DETAIL: Failing row contains (147, -10.00).
A mensagem de erro avisa que houve uma violação de restrição do tipo check.
91
6.4 NOT NULL
Por padrão o preenchimento do valor de uma coluna não é obrigatório, ou seja, é
como se declarássemos a coluna com o modificador NULL.
Para forçarmos o preenchimento de um valor de uma coluna como obrigatório
utilizamos a cláusula NOT NULL.
92
6.5 UNIQUE
Obs.:
Toda vez que uma restrição UNIQUE é criada, um índice é criado para ela
implicitamente.
Table "public.tb_unique"
Column | Type | Modifiers
--------+----------+-----------
campo1 | smallint |
campo2 | smallint |
Indexes:
"tb_unique_campo2_key" UNIQUE CONSTRAINT, btree (campo2)
A mensagem de erro informa que a restrição UNIQUE foi violada devido à tentativa
de inserção com duplicidade de valores.
93
6.6 A Cláusula [NOT] DEFERRABLE
94
Inserindo dados na tabela deferível:
> INSERT INTO tb_deferrable (x) SELECT n FROM tb_source;
Time: 10751,544 ms
Time: 11266,687 ms
Conclusão
No primeiro teste com dados repetidos o comando foi mais rápido e abortado
imediatamente, enquanto na tabela com DEFERRABLE demorou mais pois a verificação foi
feita posteriormente.
No teste sem repetição a tabela deferível se mostrou mais rápida para inserir, pois
não haviam dados repetidos que violassem a constraint UNIQUE.
95
6.7 Chave Primária / Primary Key
Seus valores são únicos (UNIQUE) e não nulos (NOT NULL), tecnicamente
podemos dizer que: PRIMARY KEY = NOT NULL + UNIQUE.
Toda vez que criamos uma chave primária um índice (index) é atribuído para a
mesma.
Verificando a estrutura:
> \d tb_pk1
Table "public.tb_pk1"
Column | Type | Modifiers
----------+----------+-----------
cod_prod | smallint | not null
preco | real |
Indexes:
"tb_pk1_pkey" PRIMARY KEY, btree (cod_prod)
Check constraints:
"tb_pk1_preco_check" CHECK (preco > 0::double precision)
Verificando a estrutura:
> \d tb_pk2
Table "public.tb_pk2"
Column | Type | Modifiers
----------+--------------+-----------
cod_prod | smallint | not null
preco | real |
Indexes:
"tb_pk2_pkey" PRIMARY KEY, btree (cod_prod)
Check constraints:
"tb_pk2_preco_check" CHECK (preco > 0::numeric)
96
Chave primária nomeando-a na criação da tabela na mesma linha do campo:
> CREATE TEMP TABLE tb_pk3(
cod_prod int2 CONSTRAINT pk_3 PRIMARY KEY,
preco float4 CHECK(preco > 0));
Verificando a estrutura:
> \d tb_pk3
Table "public.tb_pk3"
Column | Type | Modifiers
----------+--------------+-----------
cod_prod | smallint | not null
preco | real |
Indexes:
"pk_3" PRIMARY KEY, btree (cod_prod)
Check constraints:
"tb_pk3_preco_check" CHECK (preco > 0::numeric)
Verificando a estrutura:
> \d tb_pk4
Table "public.tb_pk4"
Column | Type | Modifiers
----------+--------------+-----------
cod_prod | smallint | not null
preco | real |
Indexes:
"pk_4" PRIMARY KEY, btree (cod_prod)
Check constraints:
"tb_pk4_preco_check" CHECK (preco > 0::numeric)
97
6.7.1 Chave Primária Composta
Até o momento lidamos apenas com chaves primárias simples. Ou seja, há apenas
um campo compondo a mesma.
Chaves primárias compostas têm dois ou mais campos.
Esse tipo de chave é mais utilizada em tabelas associativas.
Inserção de dados:
> INSERT INTO tb_pk_dois_campos (campo1, campo2) VALUES (0, 0), (0, 1);
98
6.8 Chave Estrangeira / Foreign Key
Apagando a tabela:
> DROP TABLE tb_venda;
99
Criação da Tabela tb_venda com a chave estrangeira previamente nomeada:
> CREATE TEMP TABLE tb_venda(
id int2 PRIMARY KEY,
produto int2,
CONSTRAINT fk_prod FOREIGN KEY (produto) REFERENCES tb_produto (id));
Table "public.tb_venda"
Column | Type | Modifiers
---------+----------+-----------
id | smallint | not null
produto | smallint |
Indexes:
"tb_venda_pkey" PRIMARY KEY, btree (id)
Foreign-key constraints:
"fk_prod" FOREIGN KEY (produto) REFERENCES tb_produto(id)
Verificando a tabela:
> \d tb_venda
Table "public.tb_venda"
Column | Type | Modifiers
---------+----------+-----------
id | smallint | not null
produto | smallint |
Indexes:
"tb_venda_pkey" PRIMARY KEY, btree (id)
100
6.8.1 Cláusulas ON DELETE / ON UPDATE
Ações:
• NO ACTION (padrão)
Produz um erro indicando que seria criada uma violação da chave estrangeira.
Se a constraint é deferida (deferred), esse erro será produzido na hora da
checagem da constraint se ainda houver quaisquer linhas de referência.
• RESTRICT
• CASCADE
• SET NULL
• SET DEFAULT
101
Inserindo dados na tabela referenciada:
> INSERT INTO tb_marca (nome) VALUES
('Ford'), ('GM'), ('Volkswagen'), ('Fiat')
RETURNING id, nome;
id | nome
----+------------
1 | Ford
2 | GM
3 | Volkswagen
4 | Fiat
id | marca | modelo
----+-------+----------
7 | 2 | Chevette
8 | 3 | Fusca
9 | 4 | 147
6 | | Corcel
id | marca | modelo
----+-------+----------
7 | 2 | Chevette
9 | 4 | 147
6 | | Corcel
8 | 33 | Fusca
102
7 SELECT – Consultas (Queries)
• Sobre SELECT
• DISTINCT
• LIMIT e OFFSET
• A Cláusula WHERE
• A Cláusula ORDER BY
• CASE: Um IF Disfarçado
• A Função coalesce
• A Função nullif
• As Funções greatest e least
• O Comando TABLE
103
7.1 Sobre SELECT
Sintaxe:
Table "public.tb_setor"
Column | Type | Modifiers
--------+-----------------------+------------------------------------------------
id | integer | not null default nextval('sq_setor'::regclass)
nome | character varying(30) |
Indexes:
"pk_setor" PRIMARY KEY, btree (id)
Referenced by:
TABLE "tb_colaborador" CONSTRAINT "fk_setor_colaborador" FOREIGN KEY (setor) REFERENCES
tb_setor(id) ON UPDATE CASCADE ON DELETE CASCADE
id | nome
----+-------------
1 | Presidência
2 | RH
3 | Logística
4 | Vendas
5 | Operações
104
Selecionando todos os campos declarando implicitamente com o caractere *:
> SELECT * FROM tb_setor;
id | nome
----+-------------
1 | Presidência
2 | RH
3 | Logística
4 | Vendas
5 | Operações
Aviso.:
105
7.2 DISTINCT
context
------------
backend
user
internal
postmaster
superuser
sighup
superuser-backend
Cada valor de context exibido tem mais de uma ocorrência, no entanto, cada um só
teve uma representação.
context | vartype
-----------+---------
sighup | integer
superuser | integer
user | string
sighup | string
user | integer
106
7.3 LIMIT e OFFSET
LIMIT e OFFSET combinados faz com que os resultados possam ser paginados,
ou seja, exibir um conjunto de linhas por vez.
LIMIT faz a limitação de quantos registros exibir.
OFFSET determina quantos ficarão de fora.
A palavra-chave OFFSET significa algo como um conjunto (set) fora (off). Ou seja,
retirar do resultado os N primeiros registros.
Unindo LIMIT e OFFSET podemos fazer paginação dos resultados com a limitação
de quantas linhas exibir com LIMIT e determinando quantos resultados ficarão de fora
com OFFSET. Assim progressivamente caminhando entre os registros.
107
7.4 A Cláusula WHERE
cpf | salario
-------------+---------
33344455511 | 4500.00
10236547895 | 3500.00
14725836944 | 3500.00
36925814788 | 1000.00
95184736277 | 1000.00
row
-----------------------
(33344455511,4500.00)
(10236547895,3500.00)
(14725836944,3500.00)
(36925814788,1000.00)
(95184736277,1000.00)
CPF e Salário
-----------------------
(33344455511,4500.00)
(10236547895,3500.00)
(14725836944,3500.00)
(36925814788,1000.00)
(95184736277,1000.00)
Por ter letras maiúsculas e espaços, foi necessário colocar o apelido da coluna
entre aspas.
108
Selecionando campos e dando apelidos mais amigáveis a eles para exibição:
> SELECT cpf AS "CPF", salario AS "Salário" FROM tb_colaborador WHERE setor = 2;
CPF | Salário
-------------+---------
33344455511 | 4500.00
10236547895 | 3500.00
14725836944 | 3500.00
36925814788 | 1000.00
95184736277 | 1000.00
Exibir cpf e id onde o cargo seja 7 e o chefe direto seja diferente de 21:
> SELECT cpf, id FROM tb_colaborador WHERE cargo = 7 AND chefe_direto != 21;
cpf | id
-------------+----
36925814788 | 7
95184736277 | 8
Conforme os campos selecionados buscar o que tiver o campo obs como não nulo:
> SELECT nome, sobrenome, cpf FROM tb_pf WHERE obs IS NOT NULL;
109
Selecionar nome, sobrenome e cpf da tabela tb_pf em que obs não seja preenchida e
genero seja igual a “f”:
> SELECT nome, sobrenome, cpf FROM tb_pf WHERE obs IS NULL AND genero = 'f';
Aviso:
Para verificar se um valor é nulo não se usa o sinal de igual “=” mas sim o operador
IS (e. g. IS NULL).
O mesmo se aplica para buscar também valores não nulos (e. g. IS NOT NULL).
id
----
3
5
6
7
8
9
10
11
12
13
14
15
110
Quando uma consulta tem mais de uma condição com a lógica OR, pode ser facilmente
substituída por IN:
> SELECT id FROM tb_colaborador WHERE setor IN (2, 3);
id
----
3
5
6
7
8
9
10
11
12
13
14
15
id
----
1
2
4
3)
> SELECT id FROM tb_colaborador
WHERE (cargo, chefe_direto, ativo) = (7, 2, true);
id
----
7
8
As três consultas são equivalentes. Na primeira o campo booleano (ativo) seu valor
foi explícito, na segunda houve uma abreviação e na terceira foi feito uso de interpolação.
111
Selecionar o id de quem tem seu salário entre 1700 a 2000:
> SELECT id FROM tb_colaborador > SELECT id FROM tb_colaborador
WHERE salario >= 1700 WHERE salario BETWEEN 1700 AND 2000;
AND salario <= 2000;
id
----
17
18
19
20
21
id
----
1
2
112
7.5 A Cláusula ORDER BY
cpf | salario
-------------+---------
36925814788 | 1000.00
95184736277 | 1000.00
10236547895 | 3500.00
14725836944 | 3500.00
33344455511 | 4500.00
cpf | salario
-------------+---------
36925814788 | 1000.00
95184736277 | 1000.00
10236547895 | 3500.00
14725836944 | 3500.00
33344455511 | 4500.00
O resultado foi o mesmo da consulta anterior, pois o efeito foi o mesmo, apenas foi
explicitada a ordem.
cpf | salario
-------------+---------
33344455511 | 4500.00
10236547895 | 3500.00
14725836944 | 3500.00
36925814788 | 1000.00
95184736277 | 1000.00
113
Ordens diferentes por campo:
> SELECT cpf, salario FROM tb_colaborador WHERE setor = 2
ORDER BY salario DESC, cpf ASC;
cpf | salario
-------------+---------
33344455511 | 4500.00
10236547895 | 3500.00
14725836944 | 3500.00
36925814788 | 1000.00
95184736277 | 1000.00
Apelidos de colunas também são considerados e podem ser utilizados como critério de
ordenamento:
> SELECT dt_nascto, nome||' '||sobrenome AS "Nome Completo"
FROM tb_pf ORDER BY "Nome Completo" LIMIT 5;
nome | sobrenome
------------+-----------
Chiquinho | da Silva
Rondonino | Sales
Tungstênia | Santana
Edervalson | Torres
Estriga | Souto
Colunas invisíveis de ordenação, são assim chamadas aquelas que são usadas
como critério de classificação, mas não aparecem no resultado. A coluna dt_nascto não
aparece no resultado.
114
7.6 CASE: Um IF Disfarçado
id | case | salario
----+-------------+----------
1 | Presidência | 20000.00
2 | Presidência | 10000.00
3 | Gerência | 4500.00
4 | Operacional | 5000.00
5 | Operacional | 3500.00
Podemos dar um apelido para a coluna deixando-a de uma forma mais legível:
> SELECT id, CASE cargo
WHEN 1 THEN 'Presidência'
WHEN 3 THEN 'Gerência'
ELSE 'Operacional'
END AS "Nível", -- Apelido para a coluna
salario FROM tb_colaborador LIMIT 5;
id | Nível | salario
----+-------------+----------
1 | Presidência | 20000.00
2 | Presidência | 10000.00
3 | Gerência | 4500.00
4 | Operacional | 5000.00
5 | Operacional | 3500.00
115
Sintaxe com operador logo após o nome do campo:
> SELECT DISTINCT
CASE
WHEN setor = 1 THEN 'Presidência'
WHEN setor = 2 THEN 'RH'
WHEN setor = 3 THEN 'Logística'
WHEN setor = 4 THEN 'Vendas'
WHEN setor = 5 THEN 'Operações'
ELSE 'Outros'
END AS "Setor"
FROM tb_colaborador;
Setor
-------------
RH
Logística
Operações
Presidência
Vendas
116
7.7 A Função coalesce
A tabela tb_pf (pessoa física) será usada, pois tem valores nulos no campo obs:
> SELECT nome, sobrenome, coalesce(obs, '...') FROM tb_pf LIMIT 5;
O comando coalesce fez com que o os valores do campo obs que são nulos
fossem mascarados. Ou seja, em de um vazio, no exemplo é exibida reticências,
conforme determinado como string do segundo parâmetro.
117
7.8 A Função nullif
É uma função que retorna um valor nulo se o primeiro valor for igual ao segundo
valor, caso contrário retornará o primeiro valor.
nullif
--------
Retorna 5:
> SELECT nullif(5, 2);
nullif
--------
5
Retorna 2:
> SELECT nullif(2, 5);
nullif
--------
2
118
7.9 As Funções greatest e least
greatest least
---------- -------
55 -9
Qual das letras é a última em ordem Qual das letras é a última em ordem
alfabética?: alfabética?:
> SELECT greatest('n', 'w', 'b'); > SELECT least('n', 'w', 'b');
greatest least
---------- -------
w b
greatest least
---------- -------
5 5
119
7.10 O Comando TABLE
id | nome
----+----------------
1 | Presidente
2 | Secretária
3 | Gerente
4 | Assistente
5 | Office boy
É possível ordernar:
> TABLE tb_cargo ORDER BY id DESC LIMIT 5;
id | nome
----+----------------
9 | Faxineiro
8 | Vendedor
7 | Ajudante Geral
6 | Moto boy
5 | Office boy
120
8 DML: Inserir, Alterar e Deletar Registros
• Sobre INSERT
• Dollar Quoting
• UPDATE – Alterando Registros
• DELETE – Removendo Registros
• A Cláusula RETURNING
• UPSERT – ON CONFLICT
121
8.1 Sobre INSERT
Sintaxe Geral:
ou
Exemplos:
Inserção em tb_pf I:
> INSERT INTO tb_pf (nome, dt_nascto, obs, cpf, rg, sobrenome, genero)
VALUES
('Alzerbina', '1960-02-22', 'Nada...', '23549878125', '7485966352', 'Marques', 'f');
122
Insert I:
> INSERT INTO tb_teste_ins (campo1, campo2, campo3) VALUES (5, now(), 'abcde');
Insert II:
> INSERT INTO tb_teste_ins (campo1, campo2, campo3)
VALUES (DEFAULT, '2012-10-17', 'xyz');
Desde a versão 8.0, o PostgreSQL suporta este recurso que facilita a inserção de
dados em uma tabela.
Seu uso consiste em, com apenas 1 (um) INSERT fazer várias inserções.
123
5 (Cinco) novos registros com 1 (Um) INSERT:
> INSERT INTO tb_teste_ins VALUES
(3, current_timestamp, current_user),
(DEFAULT, now(),'123'),
(0, '2012-07-13', '5340z'),
(478, '2002-03-01', (5 + 2)::VARCHAR),
(DEFAULT, now(), '');
124
8.2 Dollar Quoting
Dollar Quoting é uma forma alternativa de inserir strings sem usar apóstrofos e de
escapar caracteres dando uma maior segurança para o banco de dados, um grande
aliado contra um tipo de ataque conhecido como “SQL Injection”.
$$sua string$$
$marcador$sua string$marcador$
Inserindo valores:
> INSERT INTO tb_dollar_quoting VALUES
($$'teste1'$$), ($outro_marcador$'teste2'$outro_marcador$);
campo
----------
'teste1'
campo
----------
'teste2'
125
Apagando um registro:
> DELETE FROM tb_dollar_quoting
WHERE campo = $sabracadabra$'teste1'$sabracadabra$ RETURNING campo;
campo
----------
'teste1'
Atualizando um registro:
> UPDATE tb_dollar_quoting SET campo = $_123$'''Docstring Python'''$_123$
WHERE campo = $a_$'teste2'$a_$ RETURNING campo;
campo
------------------------
'''Docstring Python'''
Verificando a tabela:
> TABLE tb_dollar_quoting;
campo
------------------------
'''Docstring Python'''
apóstrofo -> '
126
8.3 UPDATE – Alterando Registros
Sintaxe Geral:
Nota-se que ao fazer uma consulta dos registros, após a atualização, os registros
afetados saíram de sua ordem original passando agora para o final de todos os registros.
Criação de tabela:
> CREATE TEMP TABLE tb_upd(cor varchar(10), temperatura int2);
127
8.4 DELETE – Removendo Registros
Para apagar linhas de uma tabela usa-se o comando DELETE, podendo inclusive usar
sub-consultas.
Sintaxe Geral:
128
8.5 A Cláusula RETURNING
É um recurso muito interessante que faz com que retorne campos inseridos,
atualizados ou apagados.
id
----
1
2
Verificando a tabela:
> TABLE tb_teste_returning;
id | campo1 | campo2
----+--------+--------
1 | foo | 452
2 | bar | 37
id | campo2
----+--------
2 | 37
129
Verificando a tabela:
> TABLE tb_teste_returning;
id | campo1 | campo2
----+--------+--------
1 | foo | 452
2 | baz | 37
id | campo1 | campo2
----+--------+--------
2 | baz | 37
Verificando a tabela:
> TABLE tb_teste_returning;
id | campo1 | campo2
----+--------+--------
1 | foo | 452
130
8.6 UPSERT – ON CONFLICT
Interessante recurso adicionado ao PostgreSQL a partir da versão 9.5.
É feita uma verificação se já existe o registro e se não existir se comporta como um
INSERT, se existe pode se comportar como um UPDATE.
Na primeira vez não teve problema, mas na segunda não foi permitido o INSERT,
pois o registro é exatamente igual, inclusive o campo id, que é único apontou um conflito.
Verificando a tabela:
> TABLE tb_upsert;
id | nome
----+-------
1 | Joana
131
Verificando a tabela:
> TABLE tb_upsert;
id | nome
----+-------
1 | Maria
Inserir um valor:
> INSERT INTO tb_upsert2 VALUES (1, 'Joana');
Verificar a tabela:
> TABLE tb_upsert2;
id | nome
----+-------
1 | Joana
Verificar a tabela:
> TABLE tb_upsert2;
id | nome
----+-------
1 | Joana
132
Inserindo com a cláusula ON CONFLICT:
> INSERT INTO tb_upsert2 VALUES (1, 'Maria')
ON CONFLICT (id) DO UPDATE SET nome = 'Maria';
Verificar a tabela:
> TABLE tb_upsert2;
id | nome
----+-------
1 | Maria
last_value | is_called
------------+-----------
1 | f
nextval
---------
1
133
Verificando o último valor dessa sequência e se ela já foi chamada:
> SELECT last_value, is_called FROM tb_upsert2_id_seq;
last_value | is_called
------------+-----------
1 | t
Após a sequência ter sido usada, o valor de is_called foi alterado para true.
Fazemos essa verificação na sequência para que não dê problemas com a chave
primária, que deve ser única.
Verificando a tabela:
> TABLE tb_upsert2;
id | nome
----+-------
1 | Maria
2 | Joana
Verificando a tabela:
> TABLE tb_upsert2;
id | nome
----+-------
1 | Sara
2 | Laura
134
9 Novas Tabelas a Partir de Dados
• Sobre Novas Tabelas a Partir de Dados
• SELECT INTO
• CREATE TABLE AS
• CREATE TABLE … (like ...)
135
9.1 Sobre Novas Tabelas a Partir de Dados
Pode surgir a necessidade de criar uma tabela cuja estrutura seja uma consulta ou
mesmo uma tabela pré existente.
SELECT INTO e CREATE TABLE AS criam uma tabela a partir de uma consulta,
mas não copiam sua estrutura.
CREATE TABLE … (like …) é capaz de copiar a estrutura da tabela de origem,
no entanto sem os dados. Isso pode ser facilmente contornado com um posterior INSERT
com SELECT na tabela criada.
136
9.2 SELECT INTO
Cria uma nova tabela, cujo nome é especificado pela cláusula INTO. Essa criação
é com base na consulta feita cujos campos terão os mesmos tipos na estrutura gerada.
Essa nova tabela não vai ter nem índices e nem constraints.
A consulta não retornou nenhuma linha, mas inseriu tudo na tabela tb_pf_mulher.
Os campos criados a partir dessa consulta são dos mesmos tipos que os campos
da tabela original.
137
9.3 CREATE TABLE AS
138
9.4 CREATE TABLE … (like …)
https://www.postgresql.org/docs/current/static/sql-createtable.html
Criação de uma nova tabela a partir da estrutura de outra com todas constraints e índices:
> CREATE TABLE tb_bar (like tb_foo INCLUDING ALL);
Estrutura de tb_foo:
> \d tb_foo
Table "pg_temp_2.tb_foo"
Column | Type | Modifiers
--------+---------+-----------------------------------------------------
id | integer | not null default nextval('tb_foo_id_seq'::regclass)
campo | integer |
Indexes:
"tb_foo_pkey" PRIMARY KEY, btree (id)
Check constraints:
"tb_foo_campo_check" CHECK (campo > 0)
Estrutura de tb_bar:
> \d tb_bar
Table "public.tb_bar"
Column | Type | Modifiers
--------+---------+-----------------------------------------------------
id | integer | not null default nextval('tb_foo_id_seq'::regclass)
campo | integer |
Indexes:
"tb_bar_pkey" PRIMARY KEY, btree (id)
Check constraints:
"tb_foo_campo_check" CHECK (campo > 0)
139
Pode-se inclusive adicionar campos extras à nova tabela criada:
> CREATE TABLE tb_baz (
like tb_foo INCLUDING ALL,
obs text);
Estrutura de tb_baz:
> \d tb_baz
Table "public.tb_baz"
Column | Type | Modifiers
--------+---------+-----------------------------------------------------
id | integer | not null default nextval('tb_foo_id_seq'::regclass)
campo | integer |
obs | text |
Indexes:
"tb_baz_pkey" PRIMARY KEY, btree (id)
Check constraints:
"tb_foo_campo_check" CHECK (campo > 0)
140
10 Conjuntos
• Sobre Conjuntos
• União (UNION)
• Intersecção (INTERSECT)
• Diferença (EXCEPT)
141
10.1 Sobre Conjuntos
query1 e query2 são consultas que podem usar qualquer uma das características
discutidas aqui.
Operações de conjunto podem também ser aninhadas ou agrupadas, por exemplo:
142
Criação de tabela temporária para múltiplos de 3:
> CREATE TEMP TABLE tb_mult3(valor int2);
143
10.2 União (UNION)
valor
-------
15
12
4
3
6
9
10
8
2
144
10.3 Intersecção (INTERSECT)
Retorna todas as linhas que estão ambas no resultado de query1 e query2. Linhas
repetidas são eliminadas a não ser que INTERSECT ALL seja usado.
valor
-------
12
6
145
10.4 Diferença (EXCEPT)
Retorna todas as linhas que estão no resultado de query1, mas não no resultado
de query2, isso é às vezes chamado de diferença entre duas consultas. Novamente,
linhas duplicadas são eliminadas a não ser que EXCEPT ALL seja usado.
Para quem vem do SGBD Oracle, essa mesma operação nele é chamada de
MINUS.
valor
-------
8
4
10
2
146
11 Casamento de Padrões e Expressões Regulares
• Sobre Casamento de Padrões e Expressões Regulares
• O Operador LIKE (~~)
• O Operador ILIKE (∼∼*)
• SIMILAR TO
• Função substring com Três Parâmetros
• Expressões Regulares POSIX
147
11.1 Sobre Casamento de Padrões e Expressões Regulares
148
11.2 LIKE (~~) e ILIKE (∼∼*)
A expressão LIKE returna true se a string casa com o padrão fornecido, que pode
ter sua lógica invertida (negada) em adição a NOT.
Se o padrão não conter sinais de porcentagem (%) ou underscores (_), então o
padrão representa apenas a string em si mesma quando LIKE atua como um operador de
igual.
O ILIKE tem como única diferença de LIKE o fato de ser case insensitive, ou
seja, não considera letras maiúsculas ou minúsculas.
Portanto, como exemplos, podem ser tomados os do LIKE, só que, logicamente,
trocando as palavras LIKE por ILIKE e invertendo na string da condição maiúsculas por
minúsculas e vice-versa.
Sintaxe:
Caracteres curinga:
?column?
----------
t
?column?
----------
t
?column?
----------
t
149
Busca de string com escape customizado:
> SELECT 'Sinal de porcentagem: %' LIKE '%|%' ESCAPE '|';
?column?
----------
t
Busca por string que tenha três caracteres e que "b" esteja no meio:
> SELECT 'abc' ~~ '_b_';
?column?
----------
t
nome
-------------
Aldebarina
Acabézia
Aldebranda
Alderovaldo
nome
------------
Carmezilda
Valverinda
Marta
Malzevino
150
Consulta para String com Caractere Especial:
> SELECT nome FROM tb_pf WHERE nome ~~ '\\%';
nome
---------------
\alguma coisa
151
11.3 SIMILAR TO
Parecido com LIKE, exceto que ele interpreta o padrão usando a norma de
definição SQL de uma expressão regular.
Expressões regulares SQL são um cruzamento curioso entre a notação LIKE e a
notação de expressão regular comum.
Como LIKE, SIMILAR TO apenas é bem-sucedido se seu padrão casar com toda
a string; o que é diferente do comportamento de uma expressão regular comum que pode
combinar qualquer parte da string.
Também como LIKE, SIMILAR TO usa os curingas "_" e "%" que denotam um
único caractere e qualquer string, respectivamente (esses são comparáveis a . e .* em
expressões regulares POSIX).
Sintaxe:
nome
-------------
Genovézio
Wolfrâmia
Tungstênia
Romirovaldo
Carmezilda
152
Condição em que o segundo caractere do nome não seja uma vogal:
> SELECT nome FROM tb_pf WHERE nome SIMILAR TO '_[^aeiou]%' LIMIT 5;
nome
------------
Aldebarina
Urânia
Estrôncio
Acabézia
Aldebranda
Condição em que o sobrenome não seja nenhum dos declarados entre parênteses,
delimitados por pipes:
> SELECT nome||' '||sobrenome AS "Nome Completo" FROM tb_pf
WHERE sobrenome NOT SIMILAR TO '%(Gomes|Santos|Silva|Guerra)' LIMIT 5;
Nome Completo
----------------------
Aldebarina Ferreira
Tungstênia Santana
Romirovaldo Ramires
Carmezilda Gonçalves
Valverinda Ramalho
153
11.4 Função substring com Três Parâmetros
Começa com “P”, tem “SQL” e pode ter mais coisas depois?:
> SELECT substring('PostgreSQL: O SGBD!' from 'P%SQL%' for '#');
---------------------
PostgreSQL: O SGBD!
Caractere de escape para trazer o texto que casa com o que há dentro do escape:
> SELECT substring('PostgreSQL: O SGBD!' from '#"P%SQL#"%' for '#');
substring
------------
PostgreSQL
Caractere de escape para trazer o texto que casa com o que há dentro do escape:
> SELECT substring('foobar' from '%#"o_b#"%' for '#');
substring
-----------
oob
Caractere de escape para trazer o texto que casa com o que há dentro do escape:
> SELECT substring('foobar' from '#"o_b#"%' for '#');
substring
-----------
O retorno foi nulo, pois não casou com toda a linha de texto.
154
11.5 Expressões Regulares POSIX
?column?
----------
t
?column?
----------
t
?column?
----------
t
155
“Uma” casa com “uma”?
> SELECT 'Uma frase qualquer' ~ 'uma';
?column?
----------
f
?column?
----------
t
Não combina?:
> SELECT 'Uma frase qualquer' !~ 'uma';
?column?
----------
t
?column?
----------
f
156
12 Subconsultas
• Sobre Subconsultas
• Subconsultas Laterais
• Subconsultas em INSERT
• Subconsultas em UPDATE
• Subconsultas em DELETE
157
12.1 Sobre Subconsultas
Aviso:
Para consultas que envolvam mais de uma tabela é uma boa prática dar apelido a
cada uma, mesmo que a mesma tabela seja usada como subconsulta de si mesma.
Exibir os CPFs dos colaboradores cujo salário seja maior do que média com 90% de
acréscimo:
> SELECT c1.cpf FROM tb_colaborador c1
WHERE salario > (SELECT (avg(c2.salario) * 1.9) FROM tb_colaborador c2);
cpf
-------------
11111111111
23625814788
12345678901
Mesmo sendo a mesma tabela (tb_colaborador), a mesma foi apelidada como “c1”
para a tabela da consulta principal e “c2” para a tabela da subconsulta e seus campos
foram chamados conforme o contexto.
158
12.1.2 Subconsulta no SELECT
O uso de uma subconsulta no FROM faz com que ela funcione como se fosse uma tabela:
> SELECT cpf FROM (SELECT * FROM tb_colaborador WHERE cargo = 1) AS tb_chefe;
cpf
-------------
11111111111
23625814788
12.1.4 EXISTS
Se existir algum registro em tb_pf cujo nome seja "Chiquinho", exibir id, cpf e salario de
tb_colaborador:
> SELECT c.id, c.cpf, c.salario FROM tb_colaborador c
WHERE EXISTS
(SELECT true FROM tb_pf p WHERE nome = 'Chiquinho')
LIMIT 5;
id | cpf | salario
----+-------------+----------
1 | 11111111111 | 20000.00
2 | 23625814788 | 10000.00
3 | 33344455511 | 4500.00
4 | 12345678901 | 5000.00
5 | 10236547895 | 3500.00
159
Exibir nome de tb_pessoa se existir algum registro em tb_colaborador que salário seja
maior que 5000 e setor seja 5:
> SELECT p.nome FROM tb_pessoa p
WHERE EXISTS
(SELECT c.cpf FROM tb_colaborador c WHERE c.salario > 5000 AND c.setor = 5);
nome
------
A condição da subconsulta não foi satisfeita, por isso também não retornou nada
para a consulta principal.
12.1.5 IN e NOT IN
A subconsulta deve retornar apenas uma coluna, cujos valores serão avaliados
para estarem (IN) ou não (NOT IN) dentro dos valores esperados.
id
----
5
10
14
22
24
id
----
9
11
12
13
15
160
12.1.6 ANY ou SOME
Tanto faz usar qualquer uma das palavras-chave, pois o efeito é o mesmo.
A subconsulta deve retornar apenas uma coluna, cujos valores serão avaliados
para a condição da consulta principal.
Se a subconsulta não trouxer nenhum resultado a consulta inteira retornará nulo.
count
-------
18
12.1.7 ALL
Exibir cpf e salário para o id 1 se o salário for maior ou igual do que qualquer linha
retornada pela subconsulta:
> SELECT c1.cpf, c1.salario FROM tb_colaborador c1
WHERE c1.id = 1 AND c1.salario >= ALL
(SELECT c2.salario FROM tb_colaborador c2 WHERE c2.setor = 1);
cpf | salario
-------------+----------
11111111111 | 20000.00
161
12.1.8 Comparação de Linha Única
A subconsulta deve retornar exatamente quantas colunas são necessárias para a
expressão à esquerda e somente uma linha. Essa linha retornada é o valor utilizado para
avaliar a expressão.
Exibir cpf e salário onde o id é 1 e se o salário for maior do que a média de toda empresa:
> SELECT c1.cpf, c1.salario FROM tb_colaborador c1
WHERE c1.id = 1
AND c1.salario > (SELECT avg(c2.salario) FROM tb_colaborador c2);
cpf | salario
-------------+----------
11111111111 | 20000.00
162
12.2 Subconsultas Laterais
Aviso:
numero | cubo
--------+------
1 | 1
2 | 8
3 | 27
4 | 64
5 | 125
6 | 216
7 | 343
8 | 512
9 | 729
10 | 1000
163
12.3 Subconsultas em INSERT
Método similar ao CREATE TABLE AS, é uma forma de passarmos dados de uma
tabela para outra.
Para exemplo, vamos primeiro criar uma tabela temporária, cuja finalidade será
conter apenas pessoas que o nome comece com a letra “A”.
Verificando os dados:
> TABLE tb_foo;
164
Inserindo uma nova linha copiando a linha onde id é igual a 1 e atribuindo o valor 2 à
coluna campo3:
> INSERT INTO tb_foo (campo1, campo2, campo3)
SELECT f.campo1, f.campo2, 2 FROM tb_foo f
WHERE f.id = 1;
O INSERT anterior é muito útil quando é preciso uma nova registro em que muitos
campos já tem seus valores que precisamos em outro registro.
Veriricando a tabela:
> TABLE tb_foo;
165
12.4 Subconsultas em UPDATE
Todos os trabalhadores que ganham menos ou igual a R$ 1.050,00 terão seus salários
reajustados para o valor igual à média daqueles que ganham menos que R$ 2.000,00:
> UPDATE tb_colaborador
SET salario = (SELECT avg(c.salario)
FROM tb_colaborador c
WHERE c.salario < 2000)
WHERE salario <= 1050;
166
A linha de id 3 será atualizada conforme a de id 1, exceto Verificando a tabela:
o campo 3 e o campo id, é claro:
> UPDATE tb_foo > TABLE tb_foo;
SET
campo1 = f.campo1, id | campo1 | campo2 | campo3
campo2 = f.campo2, ----+--------+--------+--------
campo3 = f.campo3 1 | A | A | 1
2 | B | B | 1
FROM
4 | A | A | 2
( 3 | A | A | 50
SELECT
campo1,
campo2,
50 AS campo3
FROM tb_foo
WHERE id = 1
) AS f
WHERE id = 3;
167
12.5 Subconsultas em DELETE
168
Tabelas preenchidas, agora é hora de verificar o resultado:
> SELECT t.nome AS "Time", p.nome AS "País" FROM tb_time AS t
INNER JOIN tb_pais_origem AS p
ON t.pais_origem = p.id;
Time | País
-------------------+------------
Bayern de Munique | Alemanha
Hamburgo | Alemanha
Borussia Dortmund | Alemanha
Juventus | Itália
Milan | Itália
Real Madri | Espanha
Manchester United | Inglaterra
New Castle | Inglaterra
Barcelona | Espanha
Na consulta foi usado um recurso que será visto posteriormente, que possibilita
pegar dados de diferentes tabelas em uma única consulta. Nesse caso foi usada uma
junção interna, também conhecida como INNER JOIN.
Houve um imprevisto!
Justamente os representantes dos times espanhóis, em cima da hora, avisaram
que não vão mais poder participar do torneio.
Então agora teremos que excluir esses times :(
nome
------------
Real Madri
Barcelona
169
13 Junções (Joins)
• Sobre Junções
• CROSS JOIN (Junção Cruzada)
• NATURAL JOIN (Junção Natural)
• INNER JOIN (Junção Interna)
• OUTER JOIN (Junção Externa)
• SELF JOIN (Auto Junção)
170
13.1 Sobre Junções
Junções ou Joins, em inglês, como o próprio nome diz é uma junção. Na verdade,
não somente uma, mas podem ser várias.
Junção é envolver duas ou mais tabelas em uma mesma consulta.
Ao usarmos mais de uma tabela em uma consulta pode haver nomes de colunas
idênticos nas tabelas envolvidas.
Tal inconveniente pode ser resolvido colocando o nome da tabela e um ponto antes
do nome da coluna. No entanto, muitas vezes isso pode se tornar um tanto cansativo
devido ao fato de se digitar coisas a mais, então usamos os chamados aliases de tabelas
(apelidos de tabelas).
Os apelidos de tabelas são feitos como os apelidos de colunas podendo omitir ou
não a palavra-chave AS.
171
13.2 CROSS JOIN (Junção Cruzada)
Populando sa tabelas:
> INSERT INTO tb_carro (nome) VALUES > INSERT INTO tb_cor (nome) VALUES
('Fiat 147'), ('Verde'),
('VW Fusca'), ('Azul'),
('Ford Corcel'), ('Amarelo'),
('GM Opala'); ('Branco'),
('Preto'),
('Vermelho'),
('Laranja'),
('Cinza');
Junção cruzada:
> SELECT c1.nome carro, c2.nome cor > SELECT c1.nome carro, c2.nome cor
FROM tb_carro c1 FROM tb_carro c1, tb_cor c2
CROSS JOIN LIMIT 5;
tb_cor c2
LIMIT 5;
carro | cor
----------+---------
Fiat 147 | Verde
Fiat 147 | Azul
Fiat 147 | Amarelo
Fiat 147 | Branco
Fiat 147 | Preto
Ambas as consultas são junções cruzadas mesmo que uma delas não tenha sido
explicitada como com CROSS JOIN.
172
13.3 NATURAL JOIN (Junção Natural)
Faz uma junção implícita tomando como base as colunas de mesmo nome nas
tabelas envolvidas.
É recomendável que ao invés de usar NATURAL JOIN se use INNER JOIN, pois
essa última explicita qual é o critério de vínculo entre tabelas deixando a leitura mais
amigável.
Junção natural:
> SELECT p.nome, p.sobrenome, c.salario
FROM tb_colaborador c
NATURAL JOIN tb_pf p
WHERE c.salario >= 5000;
173
13.4 INNER JOIN (Junção Interna)
174
13.5 OUTER JOIN (Junção Externa)
Assim como na INNER JOIN, existe uma ligação lógica, mas não retorna apenas
as informações que satisfaçam a regra da junção. OUTER JOINs podem ser dos tipos:
Inserção de Valores:
> INSERT INTO tb_pf VALUES
('Elzinda', '1979-05-03', NULL, '10293847567', '2233551177', 'Ambrózio', 'f'),
('Carmelita', '1915-01-01', NULL, '00000000011', '0000000011', 'Antunes', 'f'),
('Sizorfino', '1978-11-26', NULL, '00000000111', '0000000111', 'Chagas', 'm');
Nome Completo | id
---------------------------+----
Estriga Souto | 36
Eltaminácio Santos | 37
Maria dos Santos | 38
Etelvino Castro | 39
Carzózio da Silva | 40
Chiquinho da Silva | 1
\alguma coisa Bla bla bla |
Elzinda Ambrózio |
Carmelita Antunes |
Sizorfino Chagas |
Nem toda pessoa tem um id (matrícula da emprea)... Nem toda pessoa tem uma
entidade colaborador correspondente.
175
Tabela tb_colaborador à esquerda:
> SELECT p.nome||' '||p.sobrenome "Nome Completo", c.id
FROM tb_colaborador c
LEFT OUTER JOIN
tb_pf p USING (cpf) OFFSET 35;
Nome Completo | id
--------------------+----
Eltaminácio Santos | 37
Maria dos Santos | 38
Etelvino Castro | 39
Carzózio da Silva | 40
Chiquinho da Silva | 1
Nome Completo | id
--------------------+----
Eltaminácio Santos | 37
Maria dos Santos | 38
Etelvino Castro | 39
Carzózio da Silva | 40
Chiquinho da Silva | 1
Nome Completo | id
---------------------------+----
Estriga Souto | 36
Eltaminácio Santos | 37
Maria dos Santos | 38
Etelvino Castro | 39
Carzózio da Silva | 40
Chiquinho da Silva | 1
\alguma coisa Bla bla bla |
Elzinda Ambrózio |
Carmelita Antunes |
Sizorfino Chagas |
176
13.5.3 FULL OUTER JOIN (Junção Externa Total)
Nome Completo | id
---------------------------+----
Estriga Souto | 36
Eltaminácio Santos | 37
Maria dos Santos | 38
Etelvino Castro | 39
Carzózio da Silva | 40
Chiquinho da Silva | 1
\alguma coisa Bla bla bla |
Elzinda Ambrózio |
Carmelita Antunes |
Sizorfino Chagas |
Nome Completo | id
---------------------------+----
Estriga Souto | 36
Eltaminácio Santos | 37
Maria dos Santos | 38
Etelvino Castro | 39
Carzózio da Silva | 40
Chiquinho da Silva | 1
\alguma coisa Bla bla bla |
Elzinda Ambrózio |
Carmelita Antunes |
Sizorfino Chagas |
177
13.6 SELF JOIN (Auto-Junção)
Nem sempre JOINs são usadas para unir dados de duas ou mais tabelas. Há um
caso especial que se faz uma auto-junção. Ou seja, é feita uma junção de uma tabela
consigo mesma. Para evitar conflitos, usa-se aliases.
Mas ainda não está lá muito amigável... Quem é o(a) dono(a) do CPF?
178
Descobrir o nome do chefe direto de cada funcionário:
> SELECT
c1.id,
c1.cpf,
p1.nome||' '||p1.sobrenome nome_completo,
s1.nome setor,
c2.nome cargo,
c1.salario salario,
c1.dt_admis,
c1.ativo,
p2.nome||' '||p2.sobrenome "Chefe Direto"
FROM tb_colaborador c1
INNER JOIN tb_pf p1
USING (cpf)
INNER JOIN tb_setor s1
ON (c1.setor = s1.id)
INNER JOIN tb_cargo c2
ON (c1.cargo = c2.id)
INNER JOIN tb_colaborador c3
ON (c1.chefe_direto = c3.id)
INNER JOIN tb_pf p2
ON (p2.cpf = c3.cpf)
LIMIT 5;
Para conseguir exibir o nome do chefe, nesse caso, foi necessário criar um novo
apelido pra tabela tb_pf (p2), pois é nessa tabela que estão os nomes das pessoas.
179
14 Funções Built-ins
• Sobre Funções
• Funções Matemáticas
• Funções de Data e Hora
• Funções de Strings
• Funções de Sistema
180
14.1 Sobre Funções
SELECT funcao;
181
14.2 Funções Matemáticas
pow ?column?
----- ----------
8 8
sqrt ?column?
------ ----------
7 7
ceil floor
------ -------
8 7
?column? log
------------------ -----
9.42477796076938 4
mod ?column?
----- ----------
3 3
182
14.3 Funções de Data e Hora
date ?column?
------------ ------------
2015-08-17 2015-08-27
to_char
-------------------
Data: 17/08/2015 +
Hora: 14:40:29
14.3.1 extract(...)
183
14.4 Funções de Strings
trim btrim
------- -------
foo foo
Corta o caractere “x” da string à esquerda: Corta o caractere “x” da string à direita:
> SELECT ltrim('xfoox', 'x'); > SELECT rtrim('xfoox', 'x');
ltrim rtrim
------- -------
foox xfoo
Converte todos caracteres da string para Converte todos caracteres da string para
letras minúsculas: letras maiúsculas:
> SELECT lower('FOO'); > SELECT upper('foo');
lower upper
------- -------
foo FOO
initcap length
--------- --------
Foo 10
substr translate
-------- -----------
foo H4ck3r
Retornar que posição está o caractere “i”: Dada a string “23”, com 5 posições preencher
com o caractere “0” à esquerda:
> SELECT strpos('Linux', 'i');
> SELECT lpad('23', 5, '0');
strpos
--------
lpad
2
-------
00023
184
Dada a string “23”, com 5 posições String em campos, separador um espaço em
preencher com o caractere “0” à direita: branco e retornar o segundo campo:
> SELECT rpad('23', 5, '0'); > SELECT split_part('Steve Harris', ' ', 2)
AS "Sobrenome";
rpad
-------
23000 Sobrenome
-----------
Harris
14.4.1 to_char()
Essa função é tão útil, merece até tratamento especial para falar dela. Como
entrada pode-se colocar números ou datas e de acordo com a máscara inserida obtém-se
interessantes resultados.
Seu segundo argumento é do tipo text, uma máscara para modelar a conversão
desejada.
to_char to_char
----------------- --------------------
MMIX 18/08/2015 – 08:58
185
Até 9 (nove) Algarismos + 2 (duas) Casas Decimais, não Preenchidos com Zeros e
Separador de Milhar:
> SELECT to_char(29535.21,'999G999G999D99');
to_char
-----------------
29.535,21
O caractere ponto (.) é especial para uma máscara, portanto devemos colocá-lo entre
aspas para que ele seja interpretado literalmente:
> SELECT to_char(39684721495, '999"."999"."999-99') AS cpf;
cpf
-----------------
396.847.214-95
186
14.5 Funções de Sistema
version
----------------------------------------------------------------------------------------------------
PostgreSQL 9.4.4 on i686-pc-linux-gnu, compiled by gcc (Ubuntu/Linaro 4.6.3-1ubuntu5) 4.6.3, 32-bit
inet_server_addr
------------------
127.0.0.1
187
15 Agrupamentos de Dados
• Sobre Agrupamentos de Dados
• Funções de Agregação (ou de Grupos de Dados)
• A Cláusula GROUP BY
• A Cláusula HAVING
• A Cláusula FILTER
188
15.1 Sobre Agrupamentos de Dados
189
15.2 Funções de Agregação (ou de Grupos de Dados)
avg
---------
2633.57
count
-------
41
count
-------
40
cpf
-------------
11111111111
cpf
-------------
96385274133
85274136944
190
Somatória da folha de pagamento:
> SELECT sum(salario) FROM tb_colaborador;
sum
-----------
105342.80
stddev
-------------------
3338.113937755255
variance
-----------------------
11143004.661435897436
191
15.3 GROUP BY
setor | count
-------+-------
| 0
4 | 6
5 | 19
1 | 3
2 | 5
3 | 7
Quantos colaboradores ganham pelo menos R$ 2.500,00 agrupando pelo chefe direto:
chefe_direto | n_subordinados
--------------+----------------
8 | 3
1 | 7
2 | 2
192
15.4 A Cláusula HAVING
Tem por finalidade filtrar os dados agrupados impondo uma condição. Tal condição
deve ter alguma das colunas do SELECT.
Quantos colaboradores ganham pelo menos R$ 2.500,00 agrupando pelo chefe direto,
somente agrupamentos com pelo Menos 3:
> SELECT chefe_direto, count(chefe_direto) AS n_subordinados
FROM tb_colaborador
WHERE salario >= 2500
GROUP BY chefe_direto
HAVING count(chefe_direto) >= 3;
chefe_direto | n_subordinados
--------------+----------------
8 | 3
1 | 7
193
15.5 A Cláusula FILTER
194
16 SEQUENCE – Sequência
• Sobre Sequência
• Funções de Manipulação de Sequência
• Usando Sequências em Tabelas
• Alterando uma Sequência
• Apagando uma Sequência
195
16.1 Sobre Sequência
Sintaxe:
Os parâmetros:
• NO MINVALUE: Não faz uso de valores mínimos padrões, sendo que 1 e (-2 63 - 1)
para seqüências ascendentes e descendentes, respectivamente.
• CYCLE: Faz com que a sequência recomece quando for atingido o valor_máximo
ou o valor_mínimo por uma sequência ascendente ou descendente,
respectivamente. Se o limite for atingido, o próximo número gerado será o
valor_mínimo ou o valor_máximo, respectivamente.
196
Criar uma sequência temporária que se dê de 5 em 5, valor mínimo 15, valor máximo 500
e sem ciclo:
> CREATE TEMP SEQUENCE sq_teste
INCREMENT 5
MINVALUE 15
MAXVALUE 500
NO CYCLE;
197
16.2 Funções de Manipulação de Sequência
nextval
---------
20
nextval
---------
25
currval
---------
25
setval
------------
20
198
16.3 Usando Sequências em Tabelas
Dentre os tipos de dados que foram vistos, serial nada mais é do que uma
sequência criada na hora, de acordo com o nome da tabela.
Criação de Tabela:
> CREATE TEMP TABLE tb_teste_seq(
cod serial,
nome VARCHAR(15));
Table "pg_temp_3.tb_teste_seq"
Column | Type | Modifiers
--------+-----------------------+------------------------------------------------------------
cod | integer | not null default nextval('tb_teste_seq_cod_seq'::regclass)
nome | character varying(15) |
Obs.: Quando um campo de uma tabela é declarado como serial, na verdade se trata de
um campo inteiro (SMALLINT → SMALLSERIAL, INTEGER → SERIAL, BIGINT →
BIGSERIAL), para o qual é criada implicitamente uma sequência que o próximo valor
dessa sequência é seu valor padrão.
O nome dessa sequência é composto da seguinte forma:
nome_da_tabela_nome_do_campo_seq.
Apagando a Tabela:
> DROP TABLE tb_teste_seq;
199
Inserções:
> INSERT INTO tb_teste_seq (nome)
VALUES ('nome1'), ('nome2'), ('nome3'), ('nome4');
Verificando o Resultado:
> SELECT * FROM tb_teste_seq;
cod | nome
-----+-------
25 | nome1
30 | nome2
35 | nome3
40 | nome4
Como pôde ser observado, o próximo valor de cod, que é auto incremental.
200
16.4 Alterando uma Sequência
201
16.5 Apagando uma Sequência
Erro de dependência, pois a sequência não pode ser removida porque o campo
cod da tabela tb_teste_seq a tem como valor padrão conforme seu próximo retorno.
202
16.6 TRUNCATE para Reiniciar Sequências de uma Tabela
O comando TRUNCATE, como já foi visto redefine uma tabela como vazia.
O faz de uma forma muito mais inteligente e eficiente do que simplesmente um
DELETE sem WHERE.
No entanto, se na tabela que é dado o TRUNCATE, por padrão ele não reinicia as
sequências.
Isso é conseguido com a cláusula RESTART IDENTITY.
Inserir valores:
> INSERT INTO tb_sequencia (campo) VALUES ('foo'), ('bar'), ('baz');
Verificar a tabela:
> TABLE tb_sequencia;
id | campo
----+-------
1 | foo
2 | bar
3 | baz
Table "pg_temp_2.tb_sequencia"
Column | Type | Modifiers
--------+---------+-----------------------------------------------------------
id | integer | not null default nextval('tb_sequencia_id_seq'::regclass)
campo | text |
Indexes:
"tb_sequencia_pkey" PRIMARY KEY, btree (id)
203
Redefinir a tabela como vazia:
> TRUNCATE tb_sequencia;
currval
---------
3
Inserir valores:
> INSERT INTO tb_sequencia (campo) VALUES ('foo'), ('bar'), ('baz');
id | campo
----+-------
4 | foo
5 | bar
6 | baz
Apagar a tabela:
> DROP TABLE tb_sequencia;
Recriar a tabela:
> CREATE TEMP TABLE tb_sequencia (
id serial primary key,
campo text);
Inserir valores:
> INSERT INTO tb_sequencia (campo) VALUES ('foo'), ('bar'), ('baz');
204
Verificar valores da tabela:
> TABLE tb_sequencia;
id | campo
----+-------
1 | foo
2 | bar
3 | baz
Redefinir a tabela como vazia e também reiniciar todas as sequências que ela tiver:
> TRUNCATE tb_sequencia RESTART IDENTITY;
currval
---------
3
Isso faz surgir uma dúvida: será que a sequência não foi reiniciada e a situação
continuará a mesma?
Inserir valores:
> INSERT INTO tb_sequencia (campo) VALUES ('foo'), ('bar'), ('baz');
id | campo
----+-------
1 | foo
2 | bar
3 | baz
205
17 VIEW – Visão
• Sobre Visão
• Visões Materializadas
206
17.1 Sobre Visão
View ou visão, nada mais é do que uma consulta armazenada como se fosse uma
tabela virtual.
Sintaxe:
Popular a tabela:
> INSERT INTO tb_foo (campo1, campo2)
SELECT generate_series(1, 100, 3), generate_series(1, 100);
Criação da view:
> CREATE VIEW vw_foo AS
SELECT campo1, campo2
FROM tb_foo
WHERE campo2 % 19 = 0;
campo1 | campo2
--------+--------
55 | 19
10 | 38
67 | 57
22 | 76
79 | 95
207
Criação de uma visão que visualiza de forma legível dados de funcionários:
> CREATE VIEW vw_ficha_colaborador AS
SELECT
co1.id "Matrícula",
co1.cpf "CPF",
pf1.nome||' '||pf1.sobrenome "Nome completo",
se1.nome "Setor",
ca1.nome "Cargo",
pf2.nome||' '||pf2.sobrenome "Chefe direto",
co1.salario "Salario",
co1.dt_admis "Data de admissão"
FROM tb_colaborador co1
INNER JOIN tb_pf pf1 ON (co1.cpf = pf1.cpf)
INNER JOIN tb_setor se1 ON (co1.setor = se1.id)
INNER JOIN tb_cargo ca1 ON (co1.cargo = ca1.id)
INNER JOIN tb_colaborador co2 ON (co1.chefe_direto = co2.id)
INNER JOIN tb_pf pf2 ON (co2.cpf = pf2.cpf)
WHERE co1.ativo = true;
208
Uma simples consulta na nova view:
> SELECT "Nome completo", "Endereço" FROM vw_endereco_pf LIMIT 5;
Nome completo | Endereço
---------------------+----------------------------
Chiquinho da Silva | AV Álvaro Otacílio, 2900
Chiquinho da Silva | R Breves, 3541
Aldebarina Ferreira | R Simão Lopes, 2003
Wolfrâmia Santos | R dos Jornalistas, 1592
Tungstênia Santana | AV Doutor Rudge Ramos, 648
209
17.2 Visões Materializadas
Sintaxe:
[ WITH [ NO ] DATA ]
210
Inserir dados:
> INSERT INTO tb_banda (nome, origem) VALUES
('Angra', 'Brasil'),
('Shaman', 'Brasil'),
('Sepultura', 'Brasil'),
('Helloween', 'Alemanha'),
('Blind Guardian', 'Alemanha'),
('Sanctuary', 'EUA'),
('Black Sabbath', 'Inglaterra'),
('Manowar', 'EUA'),
('Kamelot', 'EUA'),
('Epica', 'Holanda'),
('Gamma Ray', 'Alemanha');
id | nome
----+-----------
1 | Angra
2 | Shaman
3 | Sepultura
id | nome
----+-----------
1 | Angra
2 | Shaman
3 | Sepultura
211
Selecionando todos os dados da view comum:
> TABLE vw_banda_br;
id | nome
----+-----------
1 | Angra
2 | Shaman
3 | Sepultura
12 | Viper
id | nome
----+-----------
1 | Angra
2 | Shaman
3 | Sepultura
id | nome
----+-----------
1 | Angra
2 | Shaman
3 | Sepultura
12 | Viper
QUERY PLAN
----------------------------------------------------------------------------------------------------
Seq Scan on tb_banda (cost=0.00..20.38 rows=4 width=36) (actual time=0.012..0.017 rows=4 loops=1)
Filter: (origem = 'Brasil'::text)
Rows Removed by Filter: 8
Planning time: 0.093 ms
Execution time: 0.045 ms
212
Exibindo o plano de execução na view materializada:
> EXPLAIN ANALYZE TABLE mv_banda_br;
QUERY PLAN
----------------------------------------------------------------------------------------------------
--------
Seq Scan on mv_banda_br (cost=0.00..22.30 rows=1230 width=36) (actual time=0.008..0.011 rows=4
loops=1)
Planning time: 0.050 ms
Execution time: 0.042 ms
213
18 Cursores
• Sobre Cursores
• FETCH – Recuperando Linhas de um Cursor
• MOVE – Movendo Cursores
• CLOSE – Fechando Cursores
214
18.1 Sobre Cursores
Sintaxe:
18.1.1 Parâmetros
• INSENSITIVE: Indica que os dados retornados pelo cursor não devem ser
afetados pelas atualizações feitas nas tabelas subjacentes ao cursor, enquanto o
cursor existir. No PostgreSQL todos os cursores são INSENSITIVE. Atualmente
esta palavra-chave não produz efeito, estando presente por motivo de
compatibilidade com o padrão SQL;
• SCROLL (rolar): Especifica que o cursor pode ser utilizado para retornar linhas de
uma maneira não sequencial (por exemplo, para trás). Dependendo da
complexidade do plano de execução do comando, especificar SCROLL pode impor
uma penalidade de desempenho no tempo de execução do comando;
• NO SCROLL: Faz com que o cursor não retorne linhas de uma maneira não
sequencial. É recomendado usar essa opção para fins de desempenho e economia
de memória quando é preciso que as linhas a serem retornadas sejam sequenciais;
• WITH HOLD: Especifica que o cursor pode continuar sendo utilizado após a
transação que o criou ter sido efetivada com sucesso ou até mesmo criar um
cursor sem estar dentro de uma transação;
• WITHOUT HOLD: Especifica que o cursor não pode ser utilizado fora da transação
que o criou. Quando não é especificado nem WITHOUT HOLD nem WITH HOLD, o
padrão é WITHOUT HOLD;
215
Obs.:
Se WITH HOLD não for especificado, o cursor criado por este comando poderá ser
utilizado somente dentro da transação corrente.
Cursores encerrados por transação são sempre fechados (efetivada ou não).
Se for especificado NO SCROLL, retornar linhas para trás não será permitido em
nenhum caso.
O padrão SQL somente trata de cursores na linguagem SQL incorporada. O
servidor PostgreSQL não implementa o comando OPEN para cursores; o cursor é
considerado aberto ao ser declarado.
Entretanto o ECPG, o pré processador do PostgreSQL para a linguagem SQL
incorporada, suporta as convenções de cursor do padrão SQL, incluindo as que envolvem
os comandos OPEN.
Sessão 1 Sessão 2
Criação de Cursor: Criação de Cursor Fora de uma Transação:
> BEGIN; > DECLARE cursor2 CURSOR WITH HOLD
DECLARE cursor1 CURSOR FOR FOR SELECT * FROM tb_colaborador;
SELECT * FROM tb_colaborador;
216
18.2 FETCH – Recuperando Linhas de um Cursor
Para tal tarefa é usado o comando FETCH, que em inglês significa buscar, trazer,
alcançar...
Sintaxe:
217
Sessão 2
Próxima linha:
> FETCH FORWARD FROM cursor2;
Próximas 7 linhas:
> FETCH FORWARD 7 FROM cursor2;
218
18.3 MOVE – Movendo Cursores
Sintaxe:
Sessão 2
219
18.4 CLOSE – Fechando Cursores
Sintaxe:
Sessão 2
Sessão 1
220
18.5 Apagando e Atualizando a Linha Onde o Cursor Aponta
campo
-------
1
2
3
4
5
Criação de cursor:
> DECLARE c1 CURSOR FOR SELECT * FROM tb_foo;
campo
-------
1
3
4
5
221
Posicionar o cursor na última linha da tabela:
> MOVE LAST c1;
Usar o cursor para atualizar a linha onde o cursor aponta Verificando a tabela:
atualmente:
> TABLE tb_foo;
> UPDATE tb_foo SET campo = 1000 WHERE CURRENT OF c1;
campo
-------
1
3
4
1000
Efetivando a transação:
> COMMIT;
222
19 BLOB
• Sobre BLOB
• Removendo BLOBs
223
19.1 Sobre BLOB
Sua utilidade está em armazenar arquivos dentro do banco de dados, sejam eles
figuras, som, executáveis ou qualquer outro.
Os dados de um blob são do tipo bytea.
Para se inserir ou recuperar blobs no PostgreSQL é necessário utilizar as funções;
lo_import(text): Seu parâmetro é a localização do arquivo a ser inserido no
banco. Essa função retorna o identificador do arquivo inserido (oid).
lo_export(oid, text): Seus parâmetros são respectivamente o oid do BLOB
e a localização futura do arquivo.
Após importar um arquivo para a base de dados, o campo da tabela só terá o oid,
que faz referência para os dados do BLOB que na verdade estão no catálogo
pg_largeobject.
Comparando com um campo bytea não é algo vantajoso para se lidar com
arquivos em bancos de dados, pois o arquivo precisa estar no servidor de banco de
dados.
pg_largeobject
Table "pg_catalog.pg_largeobject"
Column | Type | Modifiers
--------+---------+-----------
loid | oid | not null
pageno | integer | not null
data | bytea |
Indexes:
"pg_largeobject_loid_pn_index" UNIQUE, btree (loid, pageno)
224
Recuperando o objeto no diretório /tmp:
> SELECT lo_export(id_blob, '/tmp/copia_blob.png')
FROM tb_blob WHERE nome_blob = 'Figura 1';
Aviso:
225
19.2 Removendo BLOBs
Verificando a tabela:
> TABLE tb_blob;
id_blob | nome_blob
---------+-----------
16912 | Figura 1
Agora não existe mais o objeto binário, então pode-se apagar a referência a ele na
tabela tb_blob.
Apagando a referência:
> DELETE FROM tb_blob WHERE nome_blob = 'Figura 1';
226
20 Bytea
• Sobre Bytea
227
20.1 Sobre Bytea
228
Código em Python para Inserir o Arquivo na Tabela:
> # INSERIR UM BINÁRIO NO BANCO
# Exemplo em Python
# String de conexão
str_con = '''
dbname=postgres
user=postgres
host={}
password=senha'''.format(pgserver)
# Conexão ao banco
conexao = psycopg2.connect(str_con)
# Execyção do comando
cur.execute(str_sql)
# Efetivação da transação
conexao.commit()
# Fechamento de conexão
conexao.close()
arquivo
------------------
/tmp/arquivo.png
Não selecionamos também o campo dados, pois nossa visualização ficaria muito
bagunçada. Porém, vamos descobrir se realmente deu certo o que fizemos t razendo de
volta os dados que estão no campo em forma de uma cópia do arquivo.
229
Novamente no Shell Interativo de Python:
> # EXTRAIR DO BANCO PARA UM ARQUIVO
# Exemplo em Python
import psycopg2
# String de conexao
str_con = '''
dbname=postgres
user=postgres
host={}
password=senha'''.format(pgserver)
# Conexao
conexao = psycopg2.connect(str_con)
# Criação de cursor
cur = conexao.cursor()
# Dados extraídos
dados = cur.fetchone()[0]
Visualizando a Imagem:
$ eog /tmp/copia_bytea.png
230
21 COPY
• Sobre COPY
• Formato CSV
• COPY Remoto
231
21.1 Sobre COPY
O comando COPY faz a cópia de registros entre um arquivo e uma tabela, de uma
tabela para standard output = saída padrão) ou de standard input = entrada padrão) para
uma tabela.
Esse arquivo tem os campos da tabela com um delimitador conforme determinado
no comando COPY.
Sintaxe:
FORMAT format_name
OIDS [ boolean ]
FREEZE [ boolean ]
DELIMITER 'delimiter_character'
NULL 'null_string'
HEADER [ boolean ]
QUOTE 'quote_character'
ESCAPE 'escape_character'
FORCE_QUOTE { ( column_name [, ...] ) | * }
FORCE_NOT_NULL ( column_name [, ...] )
FORCE_NULL ( column_name [, ...] )
ENCODING 'encoding_name'
Aviso:
232
Terminal shell do sistema operacional:
Aviso:
Os campos são separados pelo delimitador e não pode ter espaço entre eles, pois
o espaço também é considerado como um caractere.
Terminal psql:
id | cidade | uf
----+-----------------+----
1 | São Paulo | SP
2 | Rio de Janeiro | RJ
3 | Belo Horizonte | MG
4 | Cidade Fantasma |
233
Visualizando os dados da tabela com COPY para a tela (STDOUT):
> COPY tb_copy TO STDOUT;
1 São Paulo SP
2 Rio de Janeiro RJ
3 Belo Horizonte MG
4 Cidade Fantasma \N
Dados da tabela com COPY para a tela (STDOUT) com o pipe “|” como delimitador:
> COPY tb_copy TO STDOUT DELIMITER '|';
1|São Paulo|SP
2|Rio de Janeiro|RJ
3|Belo Horizonte|MG
4|Cidade Fantasma|\N
id,cidade,uf
1,São Paulo,SP
2,Rio de Janeiro,RJ
3,Belo Horizonte,MG
4,Cidade Fantasma,--
1|São Paulo|SP
2|Rio de Janeiro|RJ
3|Belo Horizonte|MG
4|Cidade Fantasma|\N
234
Terminal psql:
id | cidade | uf
----+-----------------+----
1 | São Paulo | SP
2 | Rio de Janeiro | RJ
3 | Belo Horizonte | MG
4 | Cidade Fantasma |
Terminal psql:
235
Verificando a tabela:
> TABLE tb_copy_num_vazio;
campo_1 | campo_2
---------+---------
1 | 7
3 |
| 9
77 | 81
campo_1 | campo_2
---------+---------
3 |
| 9
Aviso:
236
21.2 Formato CSV
CSV significa Comma Separeted Values (Valores Separados por Vírgula), que no
caso são os valores respectivos aos campos de uma tabela.
Com o parâmetro CSV o arquivo resultante é gerado automaticamente com
vírgulas como delimitadores de colunas, mesmo as que estão nulas.
id | cidade | uf
----+-----------------+----
1 | São Paulo | SP
2 | Rio de Janeiro | RJ
3 | Belo Horizonte | MG
4 | Cidade Fantasma |
Os dois sinais “maior que” (>>) indicam a linha corrente para se inserir dados.
No exemplo foi determinado o formato CSV o que implica na inserção dos valores
separados por vírgula.
Para pular para a próxima linha, um novo registro, pressione <ENTER>.
Para finalizar as inserções pressione <CTRL+D>.
237
21.3 COPY Remoto
Com o comando read, exibe uma mensagem, pede uma entrada de teclado e a joga para
a variável:
$ read -p 'Digite o IP do servidor PostgreSQL: ' PGSERVER
238
Visualizando os dados da tabela no servidor remoto:
$ psql -h ${PGSERVER} -U postgres -d postgres -c 'TABLE tb_copy;'
id | cidade | uf
----+-----------------+----
1 | São Paulo | SP
2 | Rio de Janeiro | RJ
3 | Belo Horizonte | MG
4 | Cidade Fantasma |
1,São Paulo,SP
2,Rio de Janeiro,RJ
3,Belo Horizonte,MG
4,Cidade Fantasma,
239
22 Range Types - Tipos de Intervalos
• Sobre Tipos de Intervalos
240
22.1 Sobre Tipos de Intervalos
Range Types são tipos de dados que representam uma faixa de valores de algum
tipo de elemento (chamado de subtipo de faixa).
Por exemplo, faixas de timestamp que devem ser usadas para representar as
faixas de tempo que uma sala está reservada.
Nesse caso o tipo de dados é tsrange (abreviação para "timestamp range"), e
timestamp é o subtipo.
O subtipo deve ter uma ordem total para que seja bem definido se os elementos
estão dentro, antes, ou depois de faixa de valores.
Range types são úteis porque representam muitos valores de elementos em uma
única faixa de valores, e porque conceitos como sobreposição de intervalos podem ser
expressos claramente.
O uso de tempo e intervalo de dados para propósitos de agendamentos é o mais
claro exemplo; mas faixas de preços, intervalos de medidas de um instrumento, e assim
por diante podem ser úteis.
Em adição, você pode definir seus próprios range types; veja CREATE TYPE para
mais informações.
int4range
{x ∈ Z | 2 ≤ x ≤ 9}
-----------
[2,10)
241
Intervalo fechado de 2 a 9 (numeric): Representação Matemática:
> SELECT '[2, 9]'::numrange;
numrange
{x ∈ R | 2 ≤ x ≤ 9}
----------
[2,9]
int4range
{x ∈ Z | 2 < x ≤ 9}
-----------
[3,10)
numrange
{x ∈ R | 2 ≤ x ≤ 9}
----------
(2,9]
int4range
{x ∈ Z | 2 ≤ x < 9}
-----------
[2,9)
int4range
{x ∈ Z | 2 < x < 9}
-----------
[3,9)
242
Intervalos abertos em 2 e 9 (numeric): Representação Matemática:
> SELECT '(2, 9)'::numrange;
numrange
{x ∈ Z | 2 < x < 9}
----------
(2,9)
upper
-------
25
lower
-------
15
?column?
----------
f
243
22.1.5 Contenção: O Operador Contido <@
?column?
----------
t
?column?
----------
t
?column?
----------
f
22.1.7 Intersecção
?column?
----------
[15,20)
244
Visualizar o intervalo de intersecção entre os dois intervalos de datas (função daterange):
> SELECT daterange('2014-09-01', '2014-09-14', '[]') *
daterange('2014-09-10', '2014-09-20', '[]');
?column?
-------------------------
[2014-09-10,2014-09-15)
Limite inferior e superior iguais a 7 aberto no início e fechado no final (função int4range):
> SELECT int4range(7, 7, '(]');
int4range
-----------
empty
int4range
-----------
empty
isempty
---------
f
Uma faixa que tem ambos os seus limites abertos e iguais a 5 é vazia? (função isempty):
> SELECT isempty(numrange(5, 5));
isempty
---------
t
245
22.1.9 Sem Limites (Mínimo, Máximo e Ambos)
int4range
-----------
(,8)
int4range
-----------
(,8)
int4range
-----------
[7,)
int4range
-----------
[7,)
int4range
-----------
(,)
246
Sem limites:
> SELECT '(,)'::int4range;
int4range
-----------
(,)
Para fixação dos conceitos aprendidos nos exercícios anteriores, agora vamos criar uma
tabela de reservas:
> CREATE TABLE tb_reserva(
sala int PRIMARY KEY,
duracao tsrange);
Populando a tabela:
> INSERT INTO tb_reserva VALUES
(1, '[2014-11-01 14:30, 2014-11-01 18:30)'),
(2, '[2014-11-02 11:00, 2014-11-02 15:00)'),
(3, '[2014-11-03 11:00, 2014-11-03 15:00)'),
(4, '[2014-11-04 17:00, 2014-11-04 19:00)'),
(5, tsrange(
to_char(
now(),
'YYYY-MM-DD HH:mm'
)::timestamp without time zone,
to_char(
now() + '1 week'::interval,
'YYYY-MM-DD HH:mm'
)::timestamp without time zone,
'[]'
)
);
Verificando a tabela:
> TABLE tb_reserva;
sala | duracao
------+-----------------------------------------------
1 | ["2014-11-01 14:30:00","2014-11-01 18:30:00")
2 | ["2014-11-02 11:00:00","2014-11-02 15:00:00")
3 | ["2014-11-03 11:00:00","2014-11-03 15:00:00")
4 | ["2014-11-04 17:00:00","2014-11-04 19:00:00")
5 | ["2014-09-02 08:09:00","2014-09-09 08:09:00"]
247
Verificando se há alguma sala cuja data e hora esteja contida em alguma duração de
reserva:
> SELECT * FROM tb_reserva WHERE '2014-11-02 12:33'::timestamp <@ duracao;
sala | duracao
------+-----------------------------------------------
2 | ["2014-11-02 11:00:00","2014-11-02 15:00:00")
sala | duracao
------+-----------------------------------------------
3 | ["2014-11-03 11:00:00","2014-11-03 15:00:00")
248
23 Tipos de Dados Criados por Usuários
• Sobre Tipos de Dados Criados por Usuários
• Tipos Compostos (Composite Types)
• Tipos Enumerados (Enumerated Types)
• Tipos por Faixa (Range Types)
• Tipos Base (Base Types)
249
23.1 Sobre Tipos de Dados Criados por Usuários
O comando CREATE TYPE registra um novo tipo de dado para a base de dados
atual.
O usuário que o criou passa a ser seu dono.
Há cinco formas do comando CREATE TYPE, que são os tipos de dados
compostos, enumerados, de faixa, de base ou concha (shell type).
Sintaxe:
250
23.1.1 Tipo Concha (Shell Type)
Um tipo shell é apenas um espaço reservado para um tipo para ser definido mais
tarde.
Um tipo concha (shell type) é criado ao dar o comando CREATE TYPE sem
parâmetros (exceto pelo nome do tipo).
Tipos concha são necessários para referências futuras quando se cria tipos de
faixa e tipos base.
251
23.2 Tipos Compostos (Composite Types)
Populando a tabela:
> INSERT INTO tb_foo (localidade) VALUES
(('SP', 'São Paulo')),
(row('MG', 'Belo Horizonte')),
(('RO', 'Porto Velho')),
(('DF', 'Brasília')),
(row('SC', 'Florianópolis')),
(row('RJ', 'Rio de Janeiro')),
(('SP', 'Santo André'));
É opcional o uso de row para designar que é um tipo de linha (row type).
252
Consulta todos os registros da tabela:
> TABLE tb_foo;
id | localidade
----+-----------------------
1 | (SP,"São Paulo")
2 | (MG,"Belo Horizonte")
3 | (RO,"Porto Velho")
4 | (DF,Brasília)
5 | (SC,Florianópolis)
6 | (RJ,"Rio de Janeiro")
7 | (SP,"Santo André")
id | cidade
----+-------------
1 | São Paulo
7 | Santo André
253
23.3 Tipos Enumerados (Enumerated Types)
Aviso:
254
23.4 Tipos por Faixa (Range Types)
O subtipo de faixa pode ser qualquer tipo com um operador de classe b-tree
associado (para determinar o ordenamento de valores para o tipo de faixa).
Comparativo
pg_column_size
----------------
17
pg_column_size
----------------
13
Após esse comparativo podemos concluir o quanto nos vale a pena às vezes criar
um tipo de dados personalizado não só para atender nossas necessidades, mas também
para podermos ter um tipo de dado mais eficiente do que o que é oferecido por padrão.
255
23.5 Tipos Base (Base Types)
Tipo de base (base type) ou tipo escalar (scalar type) para ser criado é preciso ter
o atributo SUPERUSER. Tal restrição é feita devido ao fato de definições errôneas podem
confundir ou mesmo levar o servidor a uma falha (crash).
Os parâmetros de criação podem aparecer em qualquer ordem e a maioria é
opcional.
É possível registrar duas ou mais funções usando CREATE FUNCTION antes de
definir o tipo.
As funções de suporte input_function e output_function são obrigatórias,
enquanto que as outras são opcionais e tem que ser codificadas em C ou outra linguagem
de baixo nível.
http://www.postgresql.org/docs/current/static/sql-createtype.html
256
24 DOMAIN (Domínio)
• Sobre Domínio
• DOMAIN vs TYPE
257
24.1 Sobre Domínio
Sintaxe:
Onde constraint é:
[ CONSTRAINT nome_restrição ]
{ NOT NULL | NULL | CHECK (expressão) }
258
24.2 DOMAIN vs TYPE
Criação de um domínio, para validar CEPs que aceita inteiros com sete ou oito dígitos:
> CREATE DOMAIN dom_cep AS integer
CONSTRAINT chk_cep
CHECK (length(VALUE::text) = 7
OR length(VALUE::text) = 8);
Criação de uma tabela que usará o domínio criado como tipo de dado para uma coluna:
> CREATE TEMP TABLE tb_endereco_tmp(
id serial PRIMARY KEY,
cep dom_cep,
logradouro text,
numero smallint,
cidade varchar(50),
uf char(2));
259
Selecionando os dados:
> SELECT
to_char(cep, '00000-000') "CEP",
logradouro "Logradouro",
numero "Número",
cidade "Cidade",
uf "Estado"
FROM tb_endereco_tmp;
260
25 SCHEMA (Esquema)
• Sobre Esquemas
• Caminho de Busca de Esquema - Schema Search Path
261
25.1 Sobre Esquemas
Criação de um schema:
> CREATE SCHEMA sc_foo;
nspname
---------
public
sc_foo
List of schemas
Name | Owner
--------+----------
public | postgres
sc_foo | postgres
262
Criação de tabela de teste no schema public:
> SELECT generate_series(1, 10) campo INTO tb_foo;
campo
-------
1
2
3
4
5
campo
-------
1
3
5
7
9
List of relations
Schema | Name | Type | Owner
--------+--------+-------+----------
sc_foo | tb_foo | table | postgres
263
Lista tabelas do schema public:
> \dt
List of relations
Schema | Name | Type | Owner
--------+--------+-------+----------
public | tb_foo | table | postgres
List of relations
Schema | Name | Type | Owner
--------+--------+-------+----------
sc_foo | tb_foo | table | postgres
List of relations
Schema | Name | Type | Owner
--------+--------+-------+----------
sc_foo | tb_bar | table | postgres
sc_foo | tb_foo | table | postgres
List of relations
Schema | Name | Type | Owner
--------+--------+-------+----------
public | tb_bar | table | postgres
public | tb_foo | table | postgres
264
25.2 Caminho de Busca de Esquema - Schema Search Path
Exibe search_path:
> SHOW search_path;
search_path
----------------
"$user",public
Alterando o search_path:
> SET search_path = "$user",sc_foo,public;
Agora todos os objetos que estão em sc_foo também estarão incluídos nas buscas
da sessão corrente.
Obs.:
Listando tabelas:
> \dt
List of relations
Schema | Name | Type | Owner
--------+-----------+-------+----------
public | tb_bar | table | postgres
sc_foo | tb_foo | table | postgres
sc_foo | tb_foobar | table | postgres
265
26 MVCC
• Sobre MVCC
• Transação
• Fenômenos Indesejados em Transações
• Níveis de Isolamento
• O Conceito de ACID
• Travas
• Savepoint – Ponto de Salvamento
• SELECT … FOR UPDATE
266
26.1 Sobre MVCC
26.2 Transação
Tudo ou nada! Uma frase que define bem o que é uma transação.
Transação é uma forma de se executar uma sequência de comandos
indivisivelmente para fins de alterações, inserções ou remoções de registros.
Uma transação começa com BEGIN e termina ou com COMMIT (efetiva mudanças)
ou com ROLLBACK (não efetiva mudanças, voltando ao estado anterior à transação).
BEGIN;
comando_1;
comando2_;
. . .
comando_N;
(COMMIT | ROLLBACK)
Sintaxe de BEGIN:
267
26.2.1 Utilidade de uma transação
Por padrão, o PostgreSQL é auto commit, que significa efetivar as alterações nos
bancos de dados de forma automática, pois cada comando é executado e logo após a
alteração é feita.
No entanto, há casos que exige-se uma maior segurança, como por exemplo,
contas bancárias. Imagine uma transferência de uma conta “A” para uma conta “B” de um
valor qualquer.
No banco de dados, a conta “A” terá de seu saldo subtraído o valor da
transferência e na conta “B” adicionado. Ou seja, na primeira operação retira-se de uma e
na segunda acrescenta-se a outra.
E se logo após o valor ser subtraído de “A” houver algum problema? A conta “B”
ficaria sem o valor acrescentado e “A” ficaria com um saldo menor sem a transferência ter
sido realmente feita... Seria um grande problema para a instituição financeira!
Se no caso citado tivesse sido feito de forma a usar transação não haveria tal
transtorno, pois numa transação ou todos comandos são devidamente efetivados ou não
haverá alteração alguma. Alterações feitas durante uma transação só podem ser vistas
por quem está fazendo, os outros usuários só poderão ver depois da transação ser
efetivada. Um banco de dados relacional deve ter um mecanismo eficaz para armazenar
informações que estejam de acordo com o conceito ACID.
Dirty Read (Leitura Suja): Também conhecida como dependência não efetivada, ocorre
quando uma transação é permitida para ler dados de uma linha que foi modificada por
outra transação concorrente, mesmo que essa transação concorrente não tenha sido
efetivada. Esse fenômeno não acontece no PostgreSQL devido ao fato de não
implementar efetivamente o nível de isolamento READ UNCOMMITTED;
Nonrepeatable Read (Leitura que não se repete): Ocorre quando em uma transação
em curso uma linha buscada mais de uma vez poder retornar valores diferentes. Ou seja,
a leitura pode ter diferença dentro da transação, ela pode não se repetir. Lê linhas dentro
da transação atual que foram efetivadas com atualizações (UPDATE) por outra transação
concorrente.;
268
26.4 Níveis de Isolamento
SERIALIZABLE: Fornece o nível de isolamento mais estrito, emula uma execução serial
de transação para todas as transações efetivadas, como se fossem executadas uma após
outra serialmente, em vez de concorrentemente. Porém, como o nível REPEATABLE
READ, aplicações que usam este nível devem estar preparadas para tentar novamente as
transações devido a falhas de serialização. Na verdade, SERIALIZABLE funciona da
mesma forma que REPEATABLE READ, exceto pelo fato de monitorar condições que
possam tornar a execução de um conjunto de transações serializáveis concorrentes se
comportar de uma maneira inconsistente com tudo serial possível (um de cada vez)
execuções dessas transações. Esse monitoramento não introduz qualquer bloqueio além
do que se tem em REPEATABLE READ, mas há um certo overhead para o monitoramento,
e detecção de condições que podem causar uma falha de serialização.
269
26.5 O Conceito de ACID
ou
> SHOW transaction_isolation;
transaction_isolation
-----------------------
read committed
ou
> SET transaction_isolation = 'read committed';
Populando a tabela:
> INSERT INTO tb_mvcc (nome, idade) VALUES ('Joe', 20), ('Jill', 25);
270
Verificando os dados da tabela:
> TABLE tb_mvcc;
id | nome | idade
----+------+-------
1 | Joe | 20
2 | Jill | 25
nome
------
Joe
Jill
nome
------
Joe
Apagando um registro:
> SELECT nome FROM tb_mvcc;
nome
------
Jill
271
Verificando a tabela:
> SELECT nome FROM tb_mvcc;
nome
------
Joe
Jill
Sessão 1 Sessão 2
> BEGIN;
> SET TRANSACTION ISOLATION LEVEL READ COMMITTED;
> SELECT idade FROM tb_mvcc WHERE id = 1;
idade
-------
20
> UPDATE tb_mvcc SET idade = 21 WHERE id = 1;
> SELECT idade FROM tb_mvcc WHERE id = 1;
idade idade
------- -------
20 21
> COMMIT;
> SELECT idade FROM tb_mvcc WHERE id = 1;
idade
-------
21
> COMMIT;
272
Situação em que a transação tem seu nível de isolamento SERIALIZABLE:
Sessão 1 Sessão 2
> BEGIN;
> SET TRANSACTION ISOLATION LEVEL SERIALIZABLE;
> SELECT idade FROM tb_mvcc WHERE id = 1;
idade
-------
20
> UPDATE tb_mvcc SET idade = 21 WHERE id = 1;
> SELECT idade FROM tb_mvcc WHERE id = 1;
idade idade
------- -------
20 21
> COMMIT;
> SELECT idade FROM tb_mvcc WHERE id = 1;
idade
-------
20
> COMMIT;
> SELECT idade FROM tb_mvcc WHERE id = 1;
idade
-------
21
273
Situação em que a transação tem seu nível de isolamento REPEATABLE READ:
Sessão 1 Sessão 2
> BEGIN;
> SET TRANSACTION ISOLATION LEVEL REPEATABLE READ;
> SELECT * FROM tb_mvcc
WHERE idade BETWEEN 10 AND 30;
id | nome | idade
----+------+-------
1 | Joe | 20
2 | Jill | 25
> INSERT INTO tb_mvcc (nome, idade)
VALUES ('Maria', 27);
> SELECT * FROM tb_mvcc WHERE idade BETWEEN 10 AND 30;
id | nome | idade id | nome | idade
----+------+------- ----+-------+-------
1 | Joe | 20 1 | Joe | 20
2 | Jill | 25 2 | Jill | 25
3 | Maria | 27
> COMMIT;
> SELECT * FROM tb_mvcc
WHERE idade BETWEEN 10 AND 30;
id | nome | idade
----+------+-------
1 | Joe | 20
2 | Jill | 25
> COMMIT;
274
26.6 Travas
Travas exclusivas, também conhecidas como travas de escrita, evitam que outras
sessões modifiquem um registro ou uma tabela inteira.
Linhas modificadas por remoção (DELETE) ou atualização (UPDATE) acabam sendo
bloqueadas de forma automática e exclusiva durante a transação. Isso evita que outras
sessões possam mudar a linha até que a transação seja ou efetivada (COMMIT) ou
desfeita (ROLLBACK).
Sessão 1 Sessão 2
> BEGIN;
> SET TRANSACTION ISOLATION LEVEL READ COMMITTED;
> UPDATE tb_mvcc SET idade = 21
WHERE id = 1;
> UPDATE tb_mvcc SET idade = 22 WHERE id = 1;
Podemos ver aqui que a transação da sessão 2 está travada. E assim vai permanecer
enquanto a sessão 1 não finaliza sua transação.
> COMMIT;
> SELECT idade FROM tb_mvcc WHERE id = 1;
idade
-------
21
> COMMIT;
> SELECT idade FROM tb_mvcc WHERE id = 1;
idade
-------
22
275
Demonstração de trava (SERIALIZABLE):
Sessão 1 Sessão 2
> BEGIN;
> SET TRANSACTION ISOLATION LEVEL SERIALIZABLE;
> UPDATE tb_mvcc SET idade = 21
WHERE id = 1;
> UPDATE tb_mvcc SET idade = 22 WHERE id = 1;
Podemos ver aqui que a transação da sessão 2 está travada. E assim vai permanecer
enquanto a sessão 1 não finaliza sua transação.
> COMMIT;
ERROR: could not serialize access due to
concurrent update
Quando foi dado um COMMIT na sessão 1, na sessão 2 foi dada uma mensagem de erro
devido à atualização concorrente no nível de isolamento serializável.
> SELECT idade FROM tb_mvcc WHERE id = 1;
idade
-------
21
> COMMIT;
ROLLBACK
Em vão a sessão 2 tenta efetivar sua transação. Logo após o comando para efetivação
lê-se a mensagem ROLLBACK, indicando que a mesma não foi efetivada.
> SELECT idade FROM tb_mvcc WHERE id = 1;
idade
-------
21
276
26.7 SAVEPOINT – Ponto de Salvamento
Sintaxe:
SAVEPOINT nome_savepoint;
ROLLBACK TO SAVEPOINT
Desfaz até um ponto de salvamento nomeado, sendo que a palavra SAVEPOINT pode
ser omitida:
Obs.:
Remoção de Registro:
> DELETE FROM tb_mvcc WHERE id = 1 RETURNING nome, idade;
nome | idade
------+-------
Joe | 20
277
Verificando:
> SELECT nome, idade FROM tb_mvcc;
nome | idade
------+-------
Jill | 25
Alteração de um Registro:
> UPDATE tb_mvcc SET idade = (idade + 1) WHERE id = 2;
Verificando:
> SELECT nome, idade FROM tb_mvcc WHERE id = 2;
Verificando:
> SELECT nome, idade FROM tb_mvcc WHERE id = 2;
nome | idade
------+-------
Jill | 25
Verificando:
> SELECT nome, idade FROM tb_mvcc;
nome | idade
------+-------
Jill | 25
278
26.7.1 RELEASE SAVEPOINT
Sintaxe:
Início de Transação:
> BEGIN;
Apagando um registro:
> DELETE FROM tb_mvcc WHERE id = 1 RETURNING nome, idade;
nome | idade
------+-------
Joe | 20
Verificando:
> SELECT nome, idade FROM tb_mvcc;
nome | idade
------+-------
Jill | 25
Alteração de Registro:
> UPDATE tb_mvcc SET idade = (idade + 2) WHERE id = 2 RETURNING nome, idade;
nome | idade
------+-------
Jill | 27
279
Destruição de Ponto de Salvamento:
> RELEASE sp1;
Efetivação:
> COMMIT;
Verificando:
> SELECT * FROM tb_mvcc;
id | nome | idade
----+------+-------
2 | Jill | 27
280
26.8 SELECT ... FOR UPDATE
Sessão 1 Sessão 2
> BEGIN;
> SET TRANSACTION ISOLATION LEVEL REPEATABLE READ;
> SELECT * FROM tb_mvcc WHERE id = 1 FOR UPDATE;
id | nome | idade
----+------+-------
1 | Joe | 20
Após a efetivação dos dados pela Sessão 2 pôde finalmente fazer as alterações que
desejava.
> COMMIT;
281
27 PREPARE
• Sobre PREPARE
282
27.1 Sobre PREPARE
Sintaxe:
283
Criando um prepared statement de forma a selecionar somente bandas brasileiras:
> PREPARE q_banda_br AS SELECT * FROM tb_banda WHERE origem = 'Brasil';
id | nome | origem
----+-----------+--------
1 | Angra | Brasil
2 | Shaman | Brasil
3 | Sepultura | Brasil
12 | Viper | Brasil
14 | Wizards | Brasil
18 | Dr. Sin | Brasil
19 | Eterna | Brasil
nome
---------------
Black Sabbath
nome
-----------
Angra
Shaman
Sepultura
Viper
Wizards
Dr. Sin
Eterna
284
Visualizando todos os prepared statements da sessão:
> SELECT * FROM pg_prepared_statements;
-[ RECORD 1 ]---+----------------------------------------------------------------------
name | q_banda_id_origem
statement | PREPARE q_banda_id_origem (int, text) AS
| SELECT nome FROM tb_banda
| WHERE origem = $2 AND id > $1;
prepare_time | 2015-12-10 16:29:42.29059-02
parameter_types | {integer,text}
from_sql | t
-[ RECORD 2 ]---+----------------------------------------------------------------------
name | q_banda_id
statement | PREPARE q_banda_id (int) AS SELECT nome FROM tb_banda WHERE id = $1;
prepare_time | 2015-12-10 16:29:08.806482-02
parameter_types | {integer}
from_sql | t
-[ RECORD 3 ]---+----------------------------------------------------------------------
name | q_banda_br
statement | PREPARE q_banda_br AS SELECT * FROM tb_banda WHERE origem = 'Brasil';
prepare_time | 2015-12-10 16:27:50.151873-02
parameter_types | {}
from_sql | t
285
28 PREPARE TRANSACTION
• Sobre PREPARE TRANSACTION
286
28.1 Sobre PREPARE TRANSACTION
Sintaxe:
Aviso:
Sessão 1 Sessão 2
> BEGIN;
-[ RECORD 1 ]------------------------------
transaction | 859
gid | foo
prepared | 2015-09-04 16:49:53.272232-03
owner | postgres
database | postgres
> COMMIT PREPARED 'foo';
287
Início de transação:
> BEGIN;
Preparando a transação:
> PREPARE TRANSACTION 'bar';
Saindo da sessão:
> \q
Iniciano o serviço:
$ pg_ctl start
Cliente psql:
$ psql
288
Verificando a tabela, de forma a assegurar que o dado não tinha sido efetivamente
inserido:
> SELECT * FROM tb_banda WHERE nome = 'Anthrax';
id | nome | origem
----+------+--------
id | nome | origem
----+---------+--------
21 | Anthrax | EUA
289
29 Arrays
• Sobre Arrays
• Arrays PostgreSQL
• Inserindo Valores de Array
• Consultas em Arrays
• Modificando Arrays
• Funções de Arrays
• Operadores de Arrays
290
29.1 Sobre Arrays
Também conhecido como vetor é uma estrutura de dados que armazena uma
coleção de valores, os quais são identificados por um índice.
Cada dimensão é delimitada por colchetes "[]".
Na declaração de um array, o número entre os colchetes indica a quantidade de
elementos que esse array terá.
Quando um array tem mais de uma dimensão é chamado de matriz.
Para acessar um valor de um array ou matriz é pelo seu índice, que
tradicionalmente inicia-se por zero, de maneira que se um array foi declarado com o
tamanho 10, seus índices vão de zero a nove.
m[2][4] m={
{0, 1, 2, 3},
{4, 5, 6, 7}
}
coluna 0 coluna 1 coluna 2 coluna 3
linha 0 m[0][0] = 0 m[0][1] = 1 m[0][2] = 2 m[0][3] = 3
linha 1 m[1][0] = 4 m[1][1] = 5 m[1][2] = 6 m[1][2] = 7
291
29.2 Arrays PostgreSQL
Sintaxes de criação:
Como pôde ser notado, para criar uma coluna como array devemos adicionar os
colchetes ([]) logo após o tipo de dado.
Mesmo se especificarmos um tamanho de vetor a implementação do PostgreSQL
não força a obedecer. Nem mesmo se especificarmos que é multi-dimensional.
Table "pg_temp_2.tb_array"
Column | Type | Modifiers
---------+------------+-----------
campo_a | text |
campo_b | smallint[] |
campo_c | text[] |
Repare que para campo_c mesmo tendo especificado mais de uma dimensão, na
estrutura só consta uma.
292
29.3 Inserindo Valores de Array
typdelim
----------
,
São raríssimos os casos que o delimitador não seja a vírgula, para nossos
exercícios vamos exemplificar na sintaxe a utilizando como delimitador.
Na dúvida faça a consulta anterior especificando o tipo que utilizará no lugar de
int2.
'{
{"string_1_1", "string_1_2", "string_1_3"},
{"string_2_1", "string_2_2", "string_2_3"}
}'
array[
['string_1_1', 'string_1_2', 'string_1_3'],
['string_2_1', 'string_2_2', 'string_2_3']
]
293
O que difere de uma inserção comum é o fato de que a coluna determinada como array:
> INSERT INTO tb_array VALUES (
'bla bla bla',
'{2, 3, 4, 5}',
'{
{"texto1", "texto2", "texto3"},
{"foo", "bar", "baz"}
}'
) RETURNING campo_a, campo_b, campo_c;
campo_b
-----------
{2,3,4,5}
campo_b
---------------
{{2,3},{4,5}}
ERROR: multidimensional arrays must have array expressions with matching dimensions
294
Inserção de valores com o construtor array para inteiros (duas dimensões):
> INSERT INTO tb_array (campo_b) VALUES (
array[[1, 2, 3], [4, 5, 7]]
) RETURNING campo_b;
campo_b
-------------------
{{1,2,3},{4,5,7}}
campo_c
-------------------------
{"string 1","string 2"}
campo_c
-----------------------------------------------------------
{{"string 1_1","string 1_2"},{"string 2_1","string 2_2"}}
campo_c
-------------------------
{"string 1","string 2"}
295
Inserção de valores para texto com construtor array (duas dimensões):
> INSERT INTO tb_array (campo_c) VALUES (
array[
['string 1_1', 'string 1_2'],
['string 2_1', 'string 2_2']
]
) RETURNING campo_c;
campo_c
-----------------------------------------------------------
{{"string 1_1","string 1_2"},{"string 2_1","string 2_2"}}
296
Descrição da estrutura da tabela:
> \d tb_array
Table "pg_temp_2.tb_array"
Column | Type | Modifiers
--------+------------+-------------------------------------------------------
id | integer | not null default nextval('tb_array_id_seq'::regclass)
vetor | smallint[] |
matriz | smallint[] |
Indexes:
"tb_array_pkey" PRIMARY KEY, btree (id)
ERROR: new row for relation "tb_array" violates check constraint "ck_vetor_dim_1"
DETAIL: Failing row contains (2, {{1},{2},{3}}, null).
ERROR: new row for relation "tb_array" violates check constraint "ck_vetor_sz_3"
DETAIL: Failing row contains (2, {1,2}, null).
id | vetor | matriz
----+---------+--------
3 | {1,2,3} |
297
Criação de constraint que determina o número de dimensões para 2 (campo matriz):
> ALTER TABLE tb_array ADD CONSTRAINT ck_matriz_dim_2
CHECK (array_ndims(matriz) = 2);
ERROR: new row for relation "tb_array" violates check constraint "ck_matriz_dim_2"
DETAIL: Failing row contains (19, null, {0,1,2}).
ERROR: new row for relation "tb_array" violates check constraint "ck_matriz_col_2"
DETAIL: Failing row contains (20, null, {{0,1,NULL},{2,3,NULL},{4,5,NULL}}).
ERROR: new row for relation "tb_array" violates check constraint "ck_matriz_lin_3"
DETAIL: Failing row contains (21, null, {{0,1},{2,3}}).
298
Inserção de dados corretamente, com 2 dimensões, 3 linhas e 2 colunas:
> INSERT INTO tb_array (matriz) VALUES (array[
[0, 1], -- linha 1
[2, 3], -- linha 2
[4, 5] -- linha 3
]) RETURNING *;
id | vetor | matriz
----+-------+---------------------
7 | | {{0,1},{2,3},{4,5}}
299
29.4 Consultas em Arrays
Agora com uma tabela com campos de array, a qual foi preenchida, podemos fazer
seleções nela.
campo
---------------------------------------------------------------------------------------------
{"I 1"}
{"I 1","I 2"}
{{"I 1","I 2","I 3","I 4"},{"II 1","II 2","II 3","II 4"},{"III 1","III 2","III 3","III 4"}}
coalesce
----------
I 1
I 1
NULO
300
Verificando o segundo elemento do vetor:
> SELECT COALESCE(campo[2], 'NULO') FROM tb_array;
coalesce
----------
NULO
I 2
NULO
coalesce
----------
NULO
NULO
I 2
coalesce
----------
NULO
NULO
III 2
ou
> SELECT campo[1:1][2:3] FROM tb_array;
campo
-----------------
{}
{}
{{"I 2","I 3"}}
301
Elementos que estejam da primeira à segunda linha, da segunda à terceira coluna:
> SELECT campo[1:2][2:3] FROM tb_array;
ou
> SELECT campo[2][2:3] FROM tb_array;
campo
---------------------------------
{}
{}
{{"I 2","I 3"},{"II 2","II 3"}}
campo
-------------------
{}
{}
{{"II 2","II 3"}}
campo
--------------------
{}
{}
{{"I 2"},{"II 2"}}
302
29.5 Modificando Arrays
id | campo
----+---------
1 | {1,2,3}
id | campo
----+---------
1 | {0,2,3}
id | campo
----+-----------------------------------------------------------------------------------------
3 | {{"I 1","I 2","I 3","I 4"},{"II 1","II 2",23,"II 4"},{"III 1","III 2","III 3","III 4"}}
303
29.6 Funções de Arrays
http://www.postgresql.org/docs/current/static/functions-array.html
unnest
--------
1
2
3
4
array_length
--------------
4
array_length
--------------
2
Retorna o array passado no primeiro argumento junto com o elemento dado no segundo
parâmetro:
> SELECT array_append(array[1, 2], 3);
array_append
--------------
{1,2,3}
304
Concatenação de arrays:
> SELECT array_cat(array[1, 2, 3], ARRAY[4, 5]);
array_cat
-------------
{1,2,3,4,5}
cardinality
-------------
12
305
29.7 Operadores de Arrays
306
29.8 Alterando Tipos para Array
Imagine que após modelar uma base descobre-se que certos campos deveriam ser
arrays... Como proceder?
Caso I
Inserir dados:
> INSERT INTO tb_livro (titulo, autor) VALUES ('O Hobbit', 'Tolkien');
Tentativa de alteração do tipo de dado para o campo autor, para que o mesmo seja um
array:
> ALTER TABLE tb_livro ALTER COLUMN autor TYPE text[];
307
Verificando os dados na tabela:
> TABLE tb_livro;
id | titulo | autor
----+--------------------------+--------------------------------
1 | O Hobbit | {Tolkien}
2 | Database System Concepts | {Silberschatz,Korth,Sudarshan}
titulo
--------------------------
Database System Concepts
titulo
--------------------------
Database System Concepts
titulo
--------------------------
O Hobbit
Database System Concepts
Caso II
308
Tentativa de alteração do tipo de dado para o campo ip, para que o mesmo seja um array:
> ALTER TABLE tb_servidor ALTER COLUMN ip TYPE inet[];
id | hostname | ip
----+----------+------------------------
1 | srv00001 | {192.168.7.1}
2 | srv00001 | {192.168.7.2,10.0.0.2}
hostname
----------
srv00001
309
30 INDEX - Índice
• Sobre Índice
• Métodos de Indexação
• Índices Compostos
• Índices Parciais
• Antes de Excluir um Índice...
• Fillfactor - Fator de Preenchimento
• Reconstrução de Índices – REINDEX
• CLUSTER – Índices Clusterizados
• Excluindo um Índice
310
30.1 Sobre Índice
Um índice (INDEX) é um recurso que agiliza buscas de informações em tabelas.
Imagine que você está em uma biblioteca e gostaria de procurar “O Senhor dos
Anéis”, de Tolkien. O que seria mais fácil?: Começar a vasculhar a biblioteca inteira até
achar o livro desejado ou buscar no arquivo da biblioteca, nas fichas que estão ordenados
por autor? Logicamente se for escolhido ir buscar nas fichas a busca será muito mais
rápida, pois não será necessário vasculhar livro por livro na biblioteca, porque haverá uma
ficha do autor e daquele livro que mostrará exatamente onde está o livro desejado. É um
apontamento para a localização do livro. Um índice de banco de dados funciona da
mesma forma.
Indexamos campos usados como critérios de filtragem numa consulta (cláusula
WHERE, por exemplo) e aqueles cujos valores são mais restritivos comparados a outros
valores da tabela.
Seu funcionamento consiste em criar ponteiros para dados gravados em campos
específicos. Quando não existe índice num campo usado como critério de filtragem, é
feita uma varredura em toda a tabela, de maneira que haverá execuções de entrada e
saída (I/O) de disco desnecessárias, além de também desperdiçar processamento.
• Crie índices para campos que são utilizados em condições de consultas, pelo
menos as consultas mais frequentes;
• Crie índices para campos de chaves estrangeiras e em campos envolvidos como
critérios de junção (JOIN);
• Se houver uma consulta frequente utilize índices parciais com sua condição
conforme a consulta;
• Para consultas que buscam faixas de valores é bom ter um índice clusterizado para
isso.
Obs.:
Sintaxe:
311
Criação de tabela de teste:
> SELECT
generate_series(1, 20000)::int2 AS campo1, -- 20 mil registros
round((random()*10000))::int2 AS campo2,
round((random()*10000))::int2 AS campo3 INTO tb_index;
QUERY PLAN
--------------------------------------------------------------------------------------------------------
Seq Scan on tb_index (cost=0.00..390.71 rows=101 width=2) (actual time=0.046..8.204 rows=684 loops=1)
Filter: ((campo2 >= 235) AND (campo2 <= 587))
Rows Removed by Filter: 19316
Planning time: 0.161 ms
Execution time: 8.456 ms
QUERY PLAN
------------------------------------------------------------------------------------------------------------------
---------------
Bitmap Heap Scan on tb_index (cost=15.39..114.79 rows=693 width=2) (actual time=0.075..0.346 rows=684 loops=1)
Recheck Cond: ((campo2 >= 235) AND (campo2 <= 587))
Heap Blocks: exact=89
-> Bitmap Index Scan on idx_tb_index_campo2 (cost=0.00..15.22 rows=693 width=0) (actual time=0.064..0.064
rows=684 loops=1)
Index Cond: ((campo2 >= 235) AND (campo2 <= 587))
Planning time: 0.171 ms
Execution time: 0.437 ms
Comparando antes e depois da criação do índice, vemos que antes foi usada a
busca sequencial (Seq Scan) e levou 8.456 ms. Após criar o índice, sendo que o mesmo
foi criado para o campo utilizado na condição do WHERE, vemos que foi utilizada busca via
índice (Index Scan) e levou 0.437 ms para executar.
Por esse experimento podemos ver o quão útil é ter um índice, devido à forma
como ele agiliza uma busca.
312
30.2 Métodos de Indexação
30.2.1 BTREE
Podem lidar com consultas de faixas ou igualdades em dados que podem ser
organizados ordenadamente. Este tipo de índice deve será considerado pelo “>”.
30.2.2 GIST
Não são tipos singulares de índices, mas sim dentro de uma infra-estrutura que
muitas diferentes estratégias de indexação podem ser implementadas.
Assim, os operadores com os quais um índice GIST pode ser usado varia
dependendo da estratégia de indexação (a classe de operador).
Por exemplo, a distribuição padrão do PostgreSQL inclui classes de operadores
GIST para vários tipos de dados geométricos bi-dimensionais, que suporta consultas
usando estes operadores: &&.
30.2.3 GIN
São índices invertidos que podem lidar com valores que contenham mais de uma
chave, arrays por exemplo.
Como o GIST, pode suportar muitas estratégias diferentes de indexação definidas
por usuários e os operadores particulares com que um índice GIN pode ser usado
dependendo da estratégia de indexação. O PostgreSQL por padrão inclui classes de
operadores GIN para arrays uni-dimensionais, que suportam consultas usando estes
operadores: &&.
30.2.4 HASH
313
30.3 Índices Compostos
Sintaxe:
QUERY PLAN
------------------------------------------------------------------------------------------------------------------
---------------
Bitmap Heap Scan on tb_index (cost=15.22..116.35 rows=1 width=2) (actual time=0.475..0.475 rows=0 loops=1)
Recheck Cond: ((campo2 >= 235) AND (campo2 <= 587))
Filter: (campo3 = 1000)
Rows Removed by Filter: 684
Heap Blocks: exact=89
-> Bitmap Index Scan on idx_tb_index_campo2 (cost=0.00..15.22 rows=693 width=0) (actual time=0.104..0.104
rows=684 loops=1)
Index Cond: ((campo2 >= 235) AND (campo2 <= 587))
Planning time: 0.158 ms
Execution time: 0.500 ms
QUERY PLAN
------------------------------------------------------------------------------------------------------------------
--------------------
Index Scan using idx_tb_index_campo2_campo3 on tb_index (cost=0.29..20.96 rows=1 width=2) (actual
time=0.124..0.124 rows=0 loops=1)
Index Cond: ((campo2 >= 235) AND (campo2 <= 587) AND (campo3 = 1000))
Planning time: 0.350 ms
Execution time: 0.160 ms
314
30.4 Índices Parciais
Índice parcial é um índice que aponta para registros de acordo com uma condição.
Sintaxe:
QUERY PLAN
-----------------------------------------------------------------------------------------------------------------
Seq Scan on tb_index (cost=0.00..61065.00 rows=15930 width=4) (actual time=0.021..499.281 rows=157894 loops=1)
Filter: ((campo1 % 19) = 0)
Rows Removed by Filter: 2842106
Planning time: 0.080 ms
Execution time: 521.719 ms
Por não ter índices foi usada uma busca sequencial (Seq Scan).
315
Verifica o plano de execução:
> EXPLAIN ANALYZE SELECT * FROM tb_index WHERE campo1 % 19 = 0;
QUERY PLAN
-----------------------------------------------------------------------------------------------------------------
Seq Scan on tb_index (cost=0.00..58275.00 rows=15000 width=4) (actual time=0.019..392.215 rows=157894 loops=1)
Filter: ((campo1 % 19) = 0)
Rows Removed by Filter: 2842106
Planning time: 0.337 ms
Execution time: 413.200 ms
QUERY PLAN
------------------------------------------------------------------------------------------------------------------
Index Only Scan using idx_teste_index_19 on tb_index (cost=0.42..538.42 rows=15000 width=4) (actual
time=0.063..63.894 rows=157894 loops=1)
Heap Fetches: 157894
Planning time: 0.247 ms
Execution time: 87.157 ms
Análise com uma consulta de condição diferente de números divíveis por 19:
> EXPLAIN ANALYZE SELECT * FROM tb_index WHERE campo1 BETWEEN 241 AND 875;
QUERY PLAN
------------------------------------------------------------------------------------------------------------------
Index Only Scan using idx_teste_index_total on tb_index (cost=0.43..27.07 rows=632 width=4) (actual
time=0.018..0.450 rows=635 loops=1)
Index Cond: ((campo1 >= 241) AND (campo1 <= 875))
Heap Fetches: 635
Planning time: 0.251 ms
Execution time: 0.638 ms
Pudemos constatar o que foi dito na teoria; antes da criação dos índices a busca foi
sequencial, demorando 521.719 ms.
Após a criação dos índices, o planejador de consultas já podia contar com eles,
optando por usar o índice com maior restrição de valores levando 87.157 ms, usufruindo
de uma busca agora indexada por um índice parcial.
316
30.5 Fillfactor - Fator de Preenchimento
Table "public.tb_ff100"
Column | Type | Modifiers
--------+---------+-----------
campo | integer |
Indexes:
"idx_ff100" btree (campo) WITH (fillfactor=100)
317
Inserindo um milhão de registros:
> INSERT INTO tb_ff100 (campo) SELECT generate_series(1, 1000000);
Média: 3854.282 ms
pg_size_pretty
----------------
19 MB
Média: 6826.0742 ms
pg_size_pretty
----------------
58 MB
Parte II → Fillfactor = 50
318
Verificando nas informações de estrutura da tabela as informações sobre o índice criado
para ela:
> \d tb_ff50
Table "public.tb_ff50"
Column | Type | Modifiers
--------+---------+-----------
campo | integer |
Indexes:
"idx_ff50" btree (campo) WITH (fillfactor=50)
Média: 4256.008 ms
pg_size_pretty
----------------
39 MB
Média: 6232.7034 ms
pg_size_pretty
----------------
39 MB
319
30.6 Reconstrução de Índices – REINDEX
Sintaxe:
Onde:
Apagando a tabela:
> DROP TABLE tb_index;
Recriando a tabela:
> CREATE TABLE tb_index (campo int);
320
Inserindo valores na tabela:
> INSERT INTO tb_index (campo) SELECT generate_series(1, 1000000);
Reconstruindo o índice:
> REINDEX INDEX idx_teste;
321
30.7 CLUSTER – Índices Clusterizados
Sintaxe:
Recriando a tabela:
> CREATE TEMP TABLE tb_index(
id serial PRIMARY KEY,
cor text);
Inserindo registros:
> INSERT INTO tb_index (cor) VALUES
('Laranja'),
('Preto'),
('Branco'),
('Azul'),
('Amarelo'),
('Vermelho'),
('Verde'),
('Cinza');
id | cor
----+----------
1 | Laranja
2 | Preto
3 | Branco
4 | Azul
5 | Amarelo
6 | Vermelho
7 | Verde
8 | Cinza
322
Fazendo uma atualização:
> UPDATE tb_index SET cor = 'Vinho' WHERE id = 6;
id | cor
----+---------
1 | Laranja
2 | Preto
3 | Branco
4 | Azul
5 | Amarelo
7 | Verde
8 | Cinza
6 | Vinho
Clusterização:
> CLUSTER tb_index USING tb_index_pkey;
id | cor
----+---------
1 | Laranja
2 | Preto
3 | Branco
4 | Azul
5 | Amarelo
6 | Vinho
7 | Verde
8 | Cinza
323
30.8 Excluindo um Índice
Sintaxe:
Não remova um índice de seu banco sem antes saber o quão útil ele é.
Ou seja, se um índice já existe há um certo tempo e não tem sido usado, será
necessário replanejar o mesmo, devido à sua inutilidade.
É possível notar também que o índice parcial que foi criado em comandos
anteriores aparece como o mais usado de nossos exercícios.
Exclusão de Índice:
> DROP INDEX idx_ff50;
324
31 Modelos de Banco de Dados – Templates
• Sobre Templates
325
31.1 Sobre Templates
Sintaxe:
326
Visualizando a existência de tabelas dentro do banco recém-criado:
> \d
List of relations
Schema | Name | Type | Owner
--------+------------+-------+----------
public | tb_exemplo | table | postgres
campo
-------
1
2
3
4
5
Também podemos copiar uma base de dados tomando outra como modelo:
> CREATE DATABASE abc TEMPLATE xyz;
327
Conectando novamente a template1:
> \c template1
328
32 Herança
329
32.1 Sobre Herança de Tabelas
O PostgreSQL implementa herança de tabela, que pode ser muito útil para um
projeto de banco de dados.
O padrão SQL:1999 define um tipo de recurso de herança que difere em muitos
aspectos aos descritos aqui.
Caso I
Criação da tabela filha que dará origem a outras tabelas filhas para veículos aéreos:
> CREATE TEMP TABLE tb_veiculo_aereo(
max_altitude real)
INHERITS (tb_veiculo);
330
Criação da tabela filha que dará origem a outras tabelas filhas para veículos terrestres:
> CREATE TEMP TABLE tb_veiculo_terrestre(
n_marchas int2)
INHERITS (tb_veiculo);
Table "pg_temp_2.tb_veiculo"
Column | Type | Modifiers
--------+-----------------------+-----------
marca | character varying(30) |
modelo | character varying(40) |
Number of child tables: 2 (Use \d+ to list them.)
331
Descrição com maiores detalhes de tb_veiculo:
> \d+ tb_veiculo
Table "pg_temp_2.tb_veiculo"
Column | Type | Modifiers | Storage | Stats target | Description
--------+-----------------------+-----------+----------+--------------+-------------
marca | character varying(30) | | extended | |
modelo | character varying(40) | | extended | |
Child tables: tb_veiculo_aereo,
tb_veiculo_terrestre
Table "pg_temp_2.tb_veiculo_terrestre"
Column | Type | Modifiers | Storage | Stats target | Description
-----------+-----------------------+-----------+----------+--------------+-------------
marca | character varying(30) | | extended | |
modelo | character varying(40) | | extended | |
n_marchas | smallint | | plain | |
Inherits: tb_veiculo
Child tables: tb_carro,
tb_moto
Table "pg_temp_2.tb_veiculo_aereo"
Column | Type | Modifiers | Storage | Stats target | Description
--------------+-----------------------+-----------+----------+--------------+-------------
marca | character varying(30) | | extended | |
modelo | character varying(40) | | extended | |
max_altitude | real | | plain | |
Inherits: tb_veiculo
Child tables: tb_aviao,
tb_helicoptero
. . .
Inherits: tb_veiculo_aereo
Inherits: tb_veiculo_aereo
332
Descrição com maiores detalhes de tb_carro:
> \d+ tb_carro
. . .
Inherits: tb_veiculo_terrestre
. . .
Inherits: tb_veiculo_terrestre
333
Selecionando os dados da tabela de origem:
> SELECT marca, modelo FROM tb_veiculo;
marca | modelo
---------------------------+---------------------
Bell Helicopter | OH-58 Kiowa
Boeing Rotorcraft Systems | CH-47 Chinook
Northrop Grumman/Boeing | B-2 Spirit
Airbus Defence and Space | Eurofighter Typhoon
Fiat | 147
Ford | Corcel
Kawasaki | Z300
Harley Davidson | V-Rod
Todos os dados exibidos são de tabelas filhas das filhas, nenhum é da própria
tabela.
marca | modelo
-------+--------
Caso II
Um cadastro de cidades, sendo que para uma maior agilidade na busca foi criada
uma tabela filha somente de capitais.
A tabela de origem vai ter registros próprios.
334
Inserindo valores na tabela de capitais:
> INSERT INTO tb_capital (nome, uf, população)
VALUES ('São Paulo', 'SP', 11895893);
id | nome | uf | populacao
----+---------------------+----+-----------
1 | Santo André | SP | 707613
2 | São José dos Campos | SP | 688597
3 | São Paulo | SP | 11895893
id | nome | uf | populacao
----+---------------------+----+-----------
1 | Santo André | SP | 707613
2 | São José dos Campos | SP | 688597
id | nome | uf | populacao
----+-----------+----+-----------
3 | São Paulo | SP | 11895893
id | nome | uf | populacao
----+---------------------+----+-----------
1 | Santo André | SP | 707613
2 | São José dos Campos | SP | 688597
335
Adicionando um asterisco ao nome da tabela explicitamos que desejamos também os
dados das tabelas filhas:
> TABLE tb_cidade*;
id | nome | uf | populacao
----+---------------------+----+-----------
1 | Santo André | SP | 707613
2 | São José dos Campos | SP | 688597
3 | São Paulo | SP | 11895893
336
33 Relacionamentos
• Cardinalidade
• Relacionamento 1:1 - Um para Um
• Relacionamento 1:n - Um para Muitos
• Relacionamento n:n - Muitos para Muitos
• Relacionamento Ternário
337
33.1 Cardinalidade
Exemplos:
338
33.1.1 Simbologia
Símbolo Descrição
1: Um.
n: Vários.
339
33.2 Relacionamento 1:1 - Um para Um
Modelo Conceitual
ro a lo
f o me ene a rc ode
cp n g id m m
(0, 1) (0, 1)
Pessoa Dirige Carro
Modelo Lógico
Pessoa Carro
cpf nome genero carro_fk id marca modelo
11111111111 Chiquinho da Silva m 1 1 Fiat 147
22222222222 Maria Santos f 2 2 Volkswagen Variant
33333333333 Zé das Coves m 3 3 Ford Corcel I
44444444444 Bertolina Chaves f NULL 4 Chevrolet Chevette
55555555555 Crivélio Almeida m NULL 5 Simca Chambord
340
Modelo Físico
341
33.2.2 Relacionamento (1, 1):(0, 1)
Relacionamento obrigatório para a entidade à direita.
Modelo Conceitual
ro a lo
me ne rc de
f
cp no ge id ma mo
(1, 1) (0, 1)
Pessoa Dirige Carro
Modelo Lógico
Pessoa Carro
cpf nome genero id marca modelo pessoa_fk
11111111111 Chiquinho da Silva m 1 Fiat 147 11111111111
22222222222 Maria Santos f 2 Volkswagen Variant 22222222222
33333333333 Zé das Coves m 3 Ford Corcel I 33333333333
44444444444 Bertolina Chaves f
55555555555 Crivélio Almeida m
PessoaCarro
cpf nome genero carro_id marca modelo
11111111111 Chiquinho da Silva m 1 Fiat 147
22222222222 Maria Santos f 2 Volkswagen Variant
33333333333 Zé das Coves m 3 Ford Corcel I
44444444444 Bertolina Chaves f NULL NULL NULL
55555555555 Crivélio Almeida m NULL NULL NULL
342
Modelo Físico
343
33.2.3 Relacionamento (0, 1):(1, 1)
Relacionamento obrigatório para a entidade à esquerda.
Modelo Conceitual
ro a lo
me ne rc de
f
cp no ge id ma mo
(0, 1) (1, 1)
Pessoa Dirige Carro
Modelo Lógico
Pessoa Carro
cpf nome genero carro_fk id marca modelo
11111111111 Chiquinho da Silva m 1 1 Fiat 147
22222222222 Maria Santos f 2 2 Volkswagen Variant
33333333333 Zé das Coves m 3 3 Ford Corcel I
4 Chevrolet Chevette
5 Simca Chambord
CarroPessoa
id marca modelo cpf nome genero
1 Fiat 147 11111111111 Chiquinho da Silva m
2 Volkswagen Variant 22222222222 Maria Santos f
3 Ford Corcel I 33333333333 Zé das Coves m
4 Chevrolet Chevette NULL NULL NULL
5 Simca Chambord NULL NULL NULL
Assim como no exemplo anterior, para registros que não têm correspondência na
outra tabela, se fosse uma única tabela teriam campos nulos.
344
Modelo Físico
345
33.2.4 Relacionamento (1, 1):(1, 1)
Relacionamento obrigatório para ambos os lados.
A chave estrangeira deve estar em qualquer um dos lados.
Modelo Conceitual
ro a lo
me ne rc de
f
cp no ge id ma mo
(1, 1) (1, 1)
Pessoa Dirige Carro
Modelo Lógico
Pessoa Carro
cpf nome genero carro_fk id marca modelo
11111111111 Chiquinho da Silva m 1 1 Fiat 147
22222222222 Maria Santos f 2 2 Volkswagen Variant
33333333333 Zé das Coves m 3 3 Ford Corcel I
44444444444 Bertolina Chaves f NULL 4 Chevrolet Chevette
55555555555 Crivélio Almeida m NULL 5 Simca Chambord
CarroPessoa
id marca modelo cpf nome genero
1 Fiat 147 11111111111 Chiquinho da Silva m
2 Volkswagen Variant 22222222222 Maria Santos f
3 Ford Corcel I 33333333333 Zé das Coves m
4 Chevrolet Chevette 44444444444 Bertolina Chaves f
5 Simca Chambord 55555555555 Crivélio Almeida m
346
Modelo Físico
347
33.2.5 Cardinalidade 1:1 Como Estratégia de Particionamento
Há determinadas entidades que tem atributos que são muito mais utilizados do que
outros.
Então divide-se a tabela em duas ou mais separando seus atributos como se
fossem grupos de forma a resultar em um particionamento vertical.
Se uma tabela que representa essa entidade puder ser dividida pode trazer
benefícios:
348
33.3 Relacionamento 1:n - Um para Muitos
Uma instância de uma entidade se relaciona com várias instâncias de outra
entidade.
Modelo Conceitual
ro a lo
f o me ene a rc ode
cp n g id m m
1 n
Pessoa Dirige Carro
Modelo Lógico
Pessoa Carro
cpf nome genero id marca modelo pessoa_fk
11111111111 Chiquinho da Silva m 1 Fiat 147 11111111111
22222222222 Maria Santos f 2 Volkswagen Variant 22222222222
33333333333 Zé das Coves m 3 Ford Corcel I 33333333333
44444444444 Bertolina Chaves f 4 Chevrolet Chevette 11111111111
55555555555 Crivélio Almeida m 5 Simca Chambord NULL
349
Modelo Físico
350
33.3.2 Relacionamento (1, 1):(0, n)
Relacionamento obrigatório para a entidade da direita.
Não são permitidos valores nulos (fk) para a entidade relacionadora.
Modelo Conceitual
ro a lo
me ne rc de
f
cp no ge id ma mo
(1, 1) (0, n)
Pessoa Dirige Carro
Modelo Lógico
Pessoa Carro
cpf nome genero id marca modelo pessoa_fk
11111111111 Chiquinho da Silva m 1 Fiat 147 11111111111
22222222222 Maria Santos f 2 Volkswagen Variant 22222222222
33333333333 Zé das Coves m 3 Ford Corcel I 33333333333
44444444444 Bertolina Chaves f 4 Chevrolet Chevette 44444444444
55555555555 Crivélio Almeida m 5 Simca Chambord 55555555555
351
Modelo Físico
352
33.4 Relacionamento n:n - Muitos para Muitos
Neste tipo de relacionamento é preciso uma tabela adicional para intermediar o
relacionamento. Esse tipo de tabela é conhecido como tabela associativa.
Modelo Conceitual
e e ro c a e lo
f o m e n a r o d
cp n g id m m
n n
Pessoa Dirige Carro
Modelo Lógico
Pessoa
cpf nome genero
11111111111 Chiquinho da Silva m
22222222222 Maria Santos f
33333333333 Zé das Coves m
44444444444 Bertolina Chaves f
55555555555 Crivélio Almeida m
Carro Dirige
id marca modelo pessoa_cpf carro_id
1 Fiat 147 11111111111 1
2 Volkswagen Variant 11111111111 2
3 Ford Corcel I 33333333333 3
4 Chevrolet Chevette 44444444444 4
5 Simca Chambord 55555555555 3
353
Modelo Físico
354
33.5 Relacionamento Ternário
Tipo de relacionamento que é estabelecido entre três entidades.
Similar ao n:n, também precisa de uma tabela associativa.
Modelo Conceitual
e e r c a el
p f om en a r od
c n g id m m
o o
n n
Pessoa Dirige Carro
me
id no
n
Destino
Modelo Lógico
Pessoa
cpf nome genero
11111111111 Chiquinho da Silva m
22222222222 Maria Santos f
33333333333 Zé das Coves m
44444444444 Bertolina Chaves f
55555555555 Crivélio Almeida m
355
Modelo Físico
356