- 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 cities
y 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
serUNIQUE
o unPRIMARY KEY
, esto no detendría elcapitals
tabla de tener filas con nombres que duplican filas encities
. Y esas filas duplicadas aparecerían de forma predeterminada en las consultas decities
. De hecho, por defectocapitals
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 acapitals
, pero esto no evitaría la duplicación en comparación concities
. -
Del mismo modo, si tuviéramos que especificar que
cities
.name
REFERENCES
alguna otra tabla, esta restricción no se propagaría automáticamente acapitals
. En este caso, puede solucionarlo agregando manualmente el mismoREFERENCES
restricción acapitals
. -
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 |