Antes de usarmos o PostgreSQL, vamos ficar mais seguros cobrindo a teoria geral de banco de dados. Você não precisa entrar com nenhum código dos exemplos; eles estão lá somente com o propósito de ilustrar.
O objetivo desta lição: Compreender os conceitos fundamentais das bases de dados.
Um banco de dados consiste em uma coleção organizada de dados para um ou mais usos, tipicamente na forma digital. - Wikipedia
Um sistema gerenciador de banco de dados (SGBD) consiste em um software que opera bases de dados, proporcionando o armazenamento, acesso, segurança, backup e outras facilidades. - Wikipedia
Em bancos de dados relacionais e bases de dados em arquivos simples, uma tabela é um conjunto de elementos de dados (valores) que estão organizados usando um modelo de colunas verticais (que são identificadas por seu nome) e linhas horizontais. Uma tabela tem um número específico de colunas, mas pode ter um número qualquer de linhas. Cada linha é identificada pelos valores que aparecem em um conjunto particular de colunas que tenham sido identificadas como chaves candidatas. - Wikipedia
id | name | age
----+-------+-----
1 | Tim | 20
2 | Horst | 88
(2 rows)
Em bancos de dados SQL, uma tabela é também conhecida como uma relação.
Uma coluna é um conjunto de valores de um tipo particular de dados, um para cada linha da tabela. As colunas fornecem a estrutura com a qual as linhas são compostas. O termo “campo” é muitas vezes utilizado alternadamente com o termo “coluna”, embora muitos considerem mais correto usar campo (ou valor de campo) para se referir especificamente a um simples item que exista na interseção entre uma linha e uma coluna. - Wikipedia
Uma coluna:
| name |
+-------+
| Tim |
| Horst |
Um campo:
| Horst |
Um registro é a informação armazenada em uma linha da tabela. Cada registro terá um campo para cada coluna na tabela.
2 | Horst | 88 <-- one record
Tipos de dados restringem o tipo de informação que pode ser armazenado em uma coluna. - Tim and Horst
Existem várias classes de tipos de dados. Vamos focar nas mais comuns:
String - para armazenar dados de texto de forma livre
Integer - para armazenar números inteiros
Real - para armazenar números decinais
Date - para armazenar o aniversário de Horst para que ninguém esqueça
Boolean - para armazenar valores simples verdadeiros/falsos
You can tell the database to allow you to also store nothing in a field. If there is nothing in a field, then the field content is referred to as a ‘null’ value:
insert into person (age) values (40);
select * from person;
Resultado:
id | name | age
---+-------+-----
1 | Tim | 20
2 | Horst | 88
4 | | 40 <-- null for name
(3 rows)
There are many more datatypes you can use - check the PostgreSQL manual!
Vamos usar um estudo de caso simples para ver como um banco de dados é construído. Queremos criar um banco de dados de endereços.
Anote as propriedades que compõem um endereço simples e que gostariamos de armazenar em nosso banco de dados.
As propriedades que descrevem um endereço são as colunas. O tipo das informações armazenadas em cada coluna é o seu tipo de dado. Na próxima seção vamos analisar nossa tabela de endereços conceitual para ver como podemos fazê-la melhor!
O processo de criação de um banco de dados envolve a criação de um modelo do mundo real; tomando conceitos do mundo real e representando-os no banco de dados como entidades.
Uma das principais idéias em um banco de dados é evitar a duplicação de dados / redundância. O processo de remoção de redundância de um banco de dados é chamado de Normalização.
A normalização é uma forma sistemática de garantir que a estrutura do banco de dados é adequada para uso geral de consulta e isento de certas características indesejáveis - anomalias na inserção, atualização e exclusão - que poderia levar a uma perda de integridade dos dados. * - * Wikipedia
Existem diferentes ‘formas’ de normalização.
Let’s take a look at a simple example:
Table "public.people"
Column | Type | Modifiers
----------+------------------------+------------------------------------
id | integer | not null default
| | nextval('people_id_seq'::regclass)
| |
name | character varying(50) |
address | character varying(200) | not null
phone_no | character varying |
Indexes:
"people_pkey" PRIMARY KEY, btree (id)
select * from people;
id | name | address | phone_no
---+---------------+-----------------------------+-------------
1 | Tim Sutton | 3 Buirski Plein, Swellendam | 071 123 123
2 | Horst Duester | 4 Avenue du Roix, Geneva | 072 121 122
(2 rows)
Imagine que você tem muitos amigos com o mesmo nome de rua ou cidade. Cada vez que os dados são duplicados, consome-se espaço. Pior ainda, se um nome de cidade muda, você tem que fazer um monte de trabalho para atualizar seu banco de dados.
Redesenhando a tabela teórica people acima para reduzir a duplicação e para normalizar a estrutura de dados.
You can read more about database normalisation here
Um índice de banco de dados é uma estrutura de dados que aumenta a velocidade da operação de recuperação de dados de uma tabela de banco de dados. * - * Wikipedia
Imagine you are reading a textbook and looking for the explanation of a concept - and the textbook has no index! You will have to start reading at one cover and work your way through the entire book until you find the information you need. The index at the back of a book helps you to jump quickly to the page with the relevant information:
create index person_name_idx on people (name);
Now searches on name will be faster:
Table "public.people"
Column | Type | Modifiers
----------+------------------------+-------------------------------------
id | integer | not null default
| | nextval('people_id_seq'::regclass)
| |
name | character varying(50) |
address | character varying(200) | not null
phone_no | character varying |
Indexes:
"people_pkey" PRIMARY KEY, btree (id)
"person_name_idx" btree (name)
Uma sequência é um gerador de número único. É normalmente utilizado para criar um identificador único para uma coluna na tabela.
In this example, id is a sequence - the number is incremented each time a record is added to the table:
id | name | address | phone_no
---+--------------+-----------------------------+-------------
1 | Tim Sutton | 3 Buirski Plein, Swellendam | 071 123 123
2 | Horst Duster | 4 Avenue du Roix, Geneva | 072 121 122
In a normalised database, you typically have many relations (tables). The entity-relationship diagram (ER Diagram) is used to design the logical dependencies between the relations. Consider our non-normalised people table from earlier in the lesson:
select * from people;
id | name | address | phone_no
----+--------------+-----------------------------+-------------
1 | Tim Sutton | 3 Buirski Plein, Swellendam | 071 123 123
2 | Horst Duster | 4 Avenue du Roix, Geneva | 072 121 122
(2 rows)
With a little work we can split it into two tables, removing the need to repeat the street name for individuals who live in the same street:
select * from streets;
id | name
----+--------------
1 | Plein Street
(1 row)
e:
select * from people;
id | name | house_no | street_id | phone_no
----+--------------+----------+-----------+-------------
1 | Horst Duster | 4 | 1 | 072 121 122
(1 row)
Podemos, então, ligar as duas tabelas usando as “chaves”: kbd: streets.id e: kbd:` people.streets_id`.
Se desenharmos um Diagrama ER para essas duas tabelas, será algo parecido com isto:
O Diagrama ER nos ajuda a expressar relacionamentos “um para muitos”. Neste caso, o símbolo de seta mostra que uma rua pode ter muitas pessoas vivendo nela.
Nosso modelo people ainda tem alguns problemas de normalização - veja se você consegue normalizá-lo ainda mais e representá-lo por meio de um Diagrama ER.
Uma restrição de banco de dados é utilizada para assegurar que os dados numa relação correspondam ao ponto de vista do modelador de como que os dados devem ser armazenados. Por exemplo, uma restrição em seu código postal poderia garantir que o número caia entre: kbd: 1000 e: kbd:` 9999`.
Uma chave primária é composta de um ou mais valores de campo que tornam um registro único. Normalmente, a chave primária é chamada id e é uma sequência.
Uma chave estrangeira é usada para se referir a um único registro em outra tabela (usando a chave primária dessa outra tabela).
Em um diagrama ER, a ligação entre as tabelas é normalmente baseada em chaves estrangeiras que se ligam a chaves primárias.
If we look at our people example, the table definition shows that the street column is a foreign key that references the primary key on the streets table:
Table "public.people"
Column | Type | Modifiers
-----------+-----------------------+--------------------------------------
id | integer | not null default
| | nextval('people_id_seq'::regclass)
name | character varying(50) |
house_no | integer | not null
street_id | integer | not null
phone_no | character varying |
Indexes:
"people_pkey" PRIMARY KEY, btree (id)
Foreign-key constraints:
"people_street_id_fkey" FOREIGN KEY (street_id) REFERENCES streets(id)
Ao adicionar, alterar ou excluir dados em um banco de dados, é sempre importante que o banco de dados possa ser deixado em um estado bom se algo der errado. A maioria dos bancos de dados fornecem um recurso chamado suporte a transações. Transações permitem que você crie uma posição de “rollback” podendo voltar a esse ponto caso suas modificações ao banco de dados não ocorram conforme planejado.
Tome um cenário onde você tem um sistema de contabilidade. Você precisa transferir fundos de uma conta e adicioná-los à outro. A sequência de etapas seria assim:
remover R20 do Joe
adicionar R20 para a Anne
Se algo der errado durante o processo (por exemplo, falha de energia), a transação será revertida.
Bancos de dados permitem que você gerencie os dados de forma estruturada usando estruturas de código simples.
Agora que já vimos como bancos de dados funcionam na teoria, vamos criar um novo banco de dados para implementar a teoria que nós cobrimos.