2.5. Herança

Vamos criar duas tabelas. A tabela capitais contém as capitais dos estados, que também são cidades. Por conseguinte, a tabela capitais deve herdar da tabela cidades.

CREATE TABLE cidades (
    nome        text,
    populacao   float,
    altitude    int     -- (em pés)
);

CREATE TABLE capitais (
    estado      char(2)
) INHERITS (cidades);

Neste caso, uma linha da tabela capitais herda todos os atributos (nome, população e altitude) de sua tabela ancestral cidades. O tipo do atributo nome é text, um tipo nativo do PostgreSQL para cadeias de caracteres ASCII de tamanho variável. O tipo do atributo populacao é float, um tipo nativo do PostgreSQL para números de ponto flutuante de precisão dupla. As capitais dos estados possuem um atributo extra chamado estado, contendo a sigla do estado. No PostgreSQL uma tabela pode herdar de nenhuma, de uma, ou de várias tabelas, e uma consulta pode acessar todas as linhas de uma tabela, ou todas as linhas de uma tabela mais as linhas de suas tabelas descendentes.

Nota: A hierarquia de herança é na verdade um grafo acíclico dirigido. [1]

Por exemplo, a consulta abaixo retorna os nomes de todas as cidades, incluindo as capitais dos estados, localizadas a uma altitude superior a 500 pés:

SELECT nome, altitude
    FROM cidades
    WHERE altitude > 500;

que retorna:

   nome    | altitude
-----------+----------
 Las Vegas |     2174
 Mariposa  |     1953
 Madison   |      845

Por outro lado, a consulta abaixo retorna todas as cidades que não são capitais de estados situadas a uma altitude superior a 500 pés:

SELECT nome, altitude
    FROM ONLY cidades
    WHERE altitude > 500;

   nome    | altitude
-----------+----------
 Las Vegas |     2174
 Mariposa  |     1953

O termo ONLY antes de cidades indica que a consulta deve ser executada apenas na tabela cidades, sem incluir as tabelas descendentes de cidades na hierarquia de herança. Muitos comandos discutidos até agora -- SELECT, UPDATE e DELETE -- permitem esta notação incluindo ONLY.

Em alguns casos pode ser desejado saber de qual tabela uma determinada tupla se origina. Em cada tabela existe uma coluna do sistema chamada TABLEOID que pode informar a tabela de origem:

SELECT c.tableoid, c.nome, c.altitude
FROM cidades c
WHERE c.altitude > 500;

que retorna:

 tableoid |   nome    | altitude
----------+-----------+----------
   139793 | Las Vegas |     2174
   139793 | Mariposa  |     1953
   139798 | Madison   |      845

Se for tentada a reprodução deste exemplo, os valores numéricos dos OIDs provavelmente serão diferentes. Fazendo uma junção com a tabela "pg_class" é possível ver o nome da tabela:

SELECT p.relname, c.nome, c.altitude
FROM   cidades c, pg_class p
WHERE  c.altitude > 500 and c.tableoid = p.oid;

que retorna:

 relname  |   nome    | altitude
----------+-----------+----------
 cities   | Las Vegas |     2174
 cities   | Mariposa  |     1953
 capitals | Madison   |      845

Obsoleto: Em versões anteriores do PostgreSQL o padrão era não acessar as tabelas descendentes. Isto ocasionava muitos erros, e também era uma violação do padrão SQL. Utilizando a sintaxe antiga, para acessar as tabelas descendentes devia ser adicionado um * no final do nome da tabela. Por exemplo:

SELECT * from cidades*;

Ainda é possível especificar explicitamente a varredura das tabelas descendentes escrevendo o *, assim como especificar explicitamente a não varredura das tabelas descendentes escrevendo "ONLY" mas, a partir da versão 7.1, o comportamento padrão para um nome de tabela sem adornos passou a ser varrer as tabelas descendentes também, enquanto nas versões anteriores o padrão era não efetuar esta varredura. Para ativar o comportamento antigo deve ser definida a opção de configuração SQL_Inheritance como off. Por exemplo usar

SET SQL_Inheritance TO OFF;

ou adicionar uma linha ao arquivo postgresql.conf.

Uma limitação da funcionalidade da herança é que os índices (incluindo as restrições de unicidade) e chaves estrangeiras somente se aplicam a própria tabela, e não às suas descendentes. Portanto, no exemplo acima, especificando-se que uma coluna de outra tabela REFERENCES cidades(nome) permite à outra tabela conter nomes de cidades, mas não nomes das capitais. Esta deficiência deverá, provavelmente, ser corrigida em alguma versão futura.

Notas

[1]

Grafo: uma coleção de vértices e arestas; Grafo dirigido: um grafo com arestas unidirecionais; Grafo acíclico dirigido: um grafo dirigido que não contém ciclos - FOLDOC - Free On-Line Dictionary of Computing (N.T.)