5.10.1. Advertencias

PostgreSQL implementa la herencia de tablas, que puede ser una herramienta útil para los diseñadores de bases de datos. (SQL: 1999 y posteriores definen una característica de herencia de tipos, que difiere en muchos aspectos de las características descritas aquí).

Comencemos con un ejemplo: supongamos que estamos tratando de construir un modelo de datos para ciudades. Cada estado tiene muchas ciudades, pero solo una capital. Queremos poder recuperar rápidamente la ciudad capital de cualquier estado en particular. Esto se puede hacer creando dos tablas, una para las capitales de estado y otra para las ciudades que no son capitales. Sin embargo, ¿qué ocurre cuando queremos pedir datos sobre una ciudad, independientemente de que sea capital o no? La función de herencia puede ayudar a resolver este problema. Definimos el capitals tabla para que herede de cities:

CREATE TABLE cities (
    name            text,
    population      float,
    elevation       int     -- in feet
);

CREATE TABLE capitals (
    state           char(2)
) INHERITS (cities);

En este caso, el capitals mesa hereda todas las columnas de su tabla principal, cities. Las capitales de estado también tienen una columna adicional, state, que muestra su estado.

En PostgreSQL, una tabla puede heredar de cero o más tablas, y una consulta puede hacer referencia a todas las filas de una tabla o todas las filas de una tabla más todas sus tablas descendientes. El último comportamiento es el predeterminado. Por ejemplo, la siguiente consulta busca los nombres de todas las ciudades, incluidas las capitales de los estados, que se encuentran a una altura de más de 500 pies:

SELECT name, elevation
    FROM cities
    WHERE elevation > 500;

Dados los datos de muestra del tutorial de PostgreSQL (consulte la Sección 2.1), esto devuelve:

   name    | elevation
-----------+-----------
 Las Vegas |      2174
 Mariposa  |      1953
 Madison   |       845

Por otro lado, la siguiente consulta busca todas las ciudades que no son capitales de estado y están situadas a una altura de más de 500 pies:

SELECT name, elevation
    FROM ONLY cities
    WHERE elevation > 500;

   name    | elevation
-----------+-----------
 Las Vegas |      2174
 Mariposa  |      1953

Aquí el ONLY La palabra clave indica que la consulta debe aplicarse solo a citiesy no ninguna tabla a continuación cities en la jerarquía de herencia. Muchos de los comandos que ya hemos discutido: SELECT, UPDATE y DELETE – apoyen el ONLY palabra clave.

También puede escribir el nombre de la tabla con un final * para especificar explícitamente que se incluyen tablas descendientes:

SELECT name, elevation
    FROM cities*
    WHERE elevation > 500;

Escribiendo * no es necesario, ya que este comportamiento es siempre el predeterminado. Sin embargo, esta sintaxis todavía es compatible por compatibilidad con versiones anteriores en las que se podría cambiar el valor predeterminado.

En algunos casos, es posible que desee saber de qué tabla se originó una fila en particular. Hay una columna del sistema llamada tableoid en cada tabla que puede indicarle la tabla de origen:

SELECT c.tableoid, c.name, c.elevation
FROM cities c
WHERE c.elevation > 500;

que devuelve:

 tableoid |   name    | elevation
----------+-----------+-----------
   139793 | Las Vegas |      2174
   139793 | Mariposa  |      1953
   139798 | Madison   |       845

(Si intenta reproducir este ejemplo, probablemente obtendrá OID numéricos diferentes). Al hacer una combinación con pg_class puede ver los nombres de las tablas reales:

SELECT p.relname, c.name, c.elevation
FROM cities c, pg_class p
WHERE c.elevation > 500 AND c.tableoid = p.oid;

que devuelve:

 relname  |   name    | elevation
----------+-----------+-----------
 cities   | Las Vegas |      2174
 cities   | Mariposa  |      1953
 capitals | Madison   |       845

Otra forma de obtener el mismo efecto es utilizar el regclass tipo de alias, que imprimirá el OID de la tabla simbólicamente:

SELECT c.tableoid::regclass, c.name, c.elevation
FROM cities c
WHERE c.elevation > 500;

La herencia no propaga automáticamente los datos de INSERT o COPY comandos a otras tablas en la jerarquía de herencia. En nuestro ejemplo, lo siguiente INSERT declaración fallará:

INSERT INTO cities (name, population, elevation, state)
VALUES ('Albany', NULL, NULL, 'NY');

Es posible que esperemos que los datos se envíen de alguna manera al capitals tabla, pero esto no sucede: INSERT siempre se inserta exactamente en la tabla especificada. En algunos casos, es posible redirigir la inserción mediante una regla (ver Capítulo 40). Sin embargo, eso no ayuda para el caso anterior porque el cities la tabla no contiene la columna state, por lo que el comando será rechazado antes de que se pueda aplicar la regla.

Todas las restricciones de verificación y las restricciones no nulas en una tabla padre son heredadas automáticamente por sus hijos, a menos que se especifique explícitamente lo contrario con NO INHERIT cláusulas. Otros tipos de restricciones (restricciones de clave única, principal y externa) no se heredan.

Una tabla puede heredar de más de una tabla principal, en cuyo caso tiene la unión de las columnas definidas por las tablas principales. Todas las columnas declaradas en la definición de la tabla secundaria se agregan a estas. Si el mismo nombre de columna aparece en varias tablas principales, o tanto en una tabla principal como en la definición de la secundaria, estas columnas son fusionado de modo que solo haya una de esas columnas en la tabla secundaria. Para fusionarse, las columnas deben tener los mismos tipos de datos; de lo contrario, se genera un error. Las restricciones de comprobación heredables y las restricciones no nulas se fusionan de manera similar. Por lo tanto, por ejemplo, una columna combinada se marcará como no nula si alguna de las definiciones de columna de las que proviene está marcada como no nula. Las restricciones de verificación se combinan si tienen el mismo nombre y la combinación fallará si sus condiciones son diferentes.

La herencia de la tabla se establece normalmente cuando se crea la tabla secundaria, utilizando el INHERITS cláusula de la sentencia CREATE TABLE. Alternativamente, una tabla que ya está definida de una manera compatible puede tener una nueva relación padre agregada, usando el INHERIT variante de ALTER TABLE. Para hacer esto, la nueva tabla secundaria ya debe incluir columnas con los mismos nombres y tipos que las columnas de la principal. También debe incluir restricciones de verificación con los mismos nombres y expresiones de verificación que las del padre. De manera similar, un enlace de herencia se puede eliminar de un hijo usando el NO INHERIT variante de ALTER TABLE. Agregar y eliminar dinámicamente enlaces de herencia como este puede ser útil cuando la relación de herencia se usa para la partición de tablas (consulte la Sección 5.11).

Una forma conveniente de crear una tabla compatible que luego se convertirá en un nuevo hijo es usar el LIKE cláusula en CREATE TABLE. Esto crea una nueva tabla con las mismas columnas que la tabla de origen. Si hay alguno CHECK restricciones definidas en la tabla fuente, la INCLUDING CONSTRAINTS opción a LIKE debe especificarse, ya que el nuevo hijo debe tener restricciones que coincidan con el padre para que se considere compatible.

Una tabla principal no se puede eliminar mientras permanezcan algunos de sus elementos secundarios. Tampoco pueden eliminarse o modificarse las columnas o las restricciones de verificación de las tablas secundarias si se heredan de las tablas principales. Si desea eliminar una tabla y todos sus descendientes, una forma fácil es eliminar la tabla principal con el CASCADE opción (consulte la Sección 5.14).

ALTER TABLE propagará cualquier cambio en las definiciones de datos de columna y comprobará las restricciones en la jerarquía de herencia. De nuevo, eliminar columnas de las que dependen otras tablas solo es posible cuando se utiliza la CASCADE opción. ALTER TABLE sigue las mismas reglas para la fusión y el rechazo de columnas duplicadas que se aplican durante CREATE TABLE.

Las consultas heredadas realizan comprobaciones de permisos de acceso solo en la tabla principal. Así, por ejemplo, otorgar UPDATE permiso en el cities tabla implica permiso para actualizar filas en el capitals tabla también, cuando se accede a ellos a través de cities. Esto conserva la apariencia de que los datos están (también) en la tabla principal. Pero el capitals La tabla no se pudo actualizar directamente sin una subvención adicional. De manera similar, las políticas de seguridad de filas de la tabla principal (consulte la Sección 5.8) se aplican a las filas que provienen de las tablas secundarias durante una consulta heredada. Las políticas de una tabla secundaria, si las hay, se aplican solo cuando es la tabla nombrada explícitamente en la consulta; y en ese caso, se ignoran las políticas adjuntas a sus padres.

Las tablas externas (consulte la Sección 5.12) también pueden formar parte de las jerarquías de herencia, ya sea como tablas principales o secundarias, al igual que las tablas normales. Si una tabla foránea es parte de una jerarquía de herencia, las operaciones que no sean compatibles con la tabla foránea tampoco serán compatibles con toda la jerarquía.

5.10.1. Advertencias

Tenga en cuenta que no todos los comandos SQL pueden funcionar en jerarquías de herencia. Los comandos que se utilizan para la consulta de datos, la modificación de datos o la modificación de esquemas (p. Ej., SELECT, UPDATE, DELETE, la mayoría de variantes de ALTER TABLE, pero no INSERT o ALTER TABLE ... RENAME) normalmente incluye de forma predeterminada tablas secundarias y admite la ONLY notación para excluirlos. Los comandos que realizan el mantenimiento y ajuste de la base de datos (por ejemplo, REINDEX, VACUUM) normalmente solo funcionan en tablas físicas individuales y no admiten la recurrencia de jerarquías de herencia. El comportamiento respectivo de cada comando individual está documentado en su página de referencia (Comandos SQL).

Una limitación importante de la función de herencia es que los índices (incluidas las restricciones de unicidad) y las restricciones de clave externa solo se aplican a tablas individuales, no a sus hijos de herencia. Esto es cierto tanto en el lado de referencia como en el lado referenciado de una restricción de clave externa. Por lo tanto, en los términos del ejemplo anterior:

  • Si declaramos cities.name ser UNIQUE o un PRIMARY KEY, esto no detendría el capitals tabla de tener filas con nombres que duplican filas en cities. Y esas filas duplicadas aparecerían de forma predeterminada en las consultas de cities. De hecho, por defecto capitals no tendría ninguna restricción única y, por lo tanto, podría contener varias filas con el mismo nombre. Podría agregar una restricción única a capitals, pero esto no evitaría la duplicación en comparación con cities.

  • Del mismo modo, si tuviéramos que especificar que cities.name REFERENCES alguna otra tabla, esta restricción no se propagaría automáticamente a capitals. En este caso, puede solucionarlo agregando manualmente el mismo REFERENCES restricción a capitals.

  • Especificando que la columna de otra tabla REFERENCES cities(name) permitiría que la otra tabla contenga nombres de ciudades, pero no nombres en mayúsculas. No existe una buena solución para este caso.

Algunas funciones no implementadas para jerarquías de herencia se implementan para particiones declarativas. Es necesario tener mucho cuidado al decidir si la partición con herencia heredada es útil para su aplicación.

Anterior

Hasta próximo
5.9. Esquemas Hogar 5.11. Partición de tablas