Наследование
Наследование позволяет создавать дочерние таблицы, которые получают описания столбцов из родительской таблицы.
Например, нужно создать следующие таблицы:
CREATE TABLE books (
book_id SERIAL PRIMARY KEY,
title VARCHAR(50) NOT NULL,
author VARCHAR(50) NOT NULL);
CREATE TABLE shelves (
book_id SERIAL PRIMARY KEY,
title VARCHAR(50) NOT NULL,
author VARCHAR(50) NOT NULL,
location VARCHAR(10) NOT NULL);
Вторая таблица имеет ту же структуру, что и первая, но содержит дополнительный столбец. Можно использовать выражение INHERITS
для создания второй таблицы:
CREATE TABLE shelves (
location VARCHAR(10) NOT NULL
) INHERITS (books);
В этом случае shelves
наследует все столбцы (book_id
, title
и author
) из родительской таблицы books
. В таблице shelves
также будет дополнительный столбец — location
.
Использование выражения INHERITS
создает постоянную связь между новой дочерней таблицей и родительской таблицей. Изменения родительской схемы распространяются на дочернюю таблицу, и данные дочерней таблицы включаются в сканирование родительской.
Добавим данные в таблицы:
INSERT INTO books (title, author) VALUES
('Hyperion', 'Dan Simmons'),
('1984', 'George Orwell');
INSERT INTO shelves (title, author, location) VALUES
('The Time Machine', 'Herbert George Wells', 'B32'),
('The Great Gatsby', 'F. Scott Fitzgerald', 'C14');
Получим данные из таблицы books
:
SELECT * FROM books;
Результат также включает строки из таблицы shelves
:
book_id | title | author ---------+------------------+---------------------- 1 | Hyperion | Dan Simmons 2 | 1984 | George Orwell 3 | The Great Gatsby | F. Scott Fitzgerald 4 | The Time Machine | Herbert George Wells
Запрос возвращает все строки родительской таблицы и её наследника.
Чтобы вернуть только строки родительской таблицы, используйте ключевое слово ONLY
:
SELECT * FROM ONLY books;
Результат:
book_id | title | author ---------+----------+--------------- 1 | Hyperion | Dan Simmons 2 | 1984 | George Orwell
Можно использовать системный столбец tableoid
и данные из каталога pg_class, чтобы определить, из какой таблицы каждая строка:
SELECT p.relname, b.title
FROM books b, pg_class p
WHERE b.tableoid = p.oid;
Результат:
relname | title ---------+------------------ books | Hyperion books | 1984 shelves | The Great Gatsby shelves | The Time Machine
Родительские таблицы могут быть обычными таблицами или внешними таблицами. Таблица может наследовать столбцы из нескольких родительских таблиц. Если одно и то же имя столбца существует более чем в одной родительской таблице, и типы данных столбцов не совпадают, выдается сообщение об ошибке. Если конфликта нет, повторяющиеся столбцы объединяются в один столбец в дочерней таблице.
Если список имен столбцов дочерней таблицы содержит имя столбца, которое также унаследовано от родителя, тип данных этих столбцов должен совпадать. Определения таких столбцов объединяются в одно. Если в новой таблице явно указано значение по умолчанию для столбца, оно переопределяет любые значения по умолчанию из унаследованных определений.
Дочерние таблицы наследуют все ограничения CHECK
и NOT NULL
родительской таблицы, если только описание ограничения не содержит выражение NO INHERIT
. Другие типы ограничений (UNIQUE
, PRIMARY KEY
и FOREIGN KEY
) не наследуются.
Столбцы и ограничения CHECK
дочерних таблиц нельзя удалить или изменить, если они унаследованы от родительских таблиц.
Также можно добавить родительскую связь к таблице, которая уже создана с совместимой структурой. Дочерняя таблица должна включать столбцы с теми же именами и типами, что и столбцы родительской таблицы.Для этой цели используется выражение INHERIT
в команде ALTER TABLE
:
CREATE TABLE books2 (
book_id SERIAL PRIMARY KEY,
title VARCHAR(50) NOT NULL,
author VARCHAR(50) NOT NULL);
CREATE TABLE shelves2 (
book_id SERIAL PRIMARY KEY,
title VARCHAR(50) NOT NULL,
author VARCHAR(50) NOT NULL,
location VARCHAR(10) NOT NULL);
ALTER TABLE shelves2 INHERIT books2;
Операции с таблицами, созданными путем наследования, имеют следующую специфику:
-
Команды
SELECT
,UPDATE
иDELETE
, которые выполняются над родительской таблицей, также выполняются над дочерними таблицами. Можно использовать ключевое словоONLY
, чтобы избежать такого поведения.Команды
INSERT
иCOPY
, выполненные для родительской таблицы, не работают с дочерними таблицами. -
PostgreSQL не проверяет права доступа для дочерних таблиц при их обработке через родительскую таблицу. Например, предоставление разрешения
UPDATE
для таблицыbooks
подразумевает разрешение на обновление строк в таблицеshelves
, когда к ним обращаются черезbooks
. -
PostgreSQL не может удалить родительскую таблицу, пока у неё остаются дочерние. Чтобы удалить таблицу и всех её наследников, удалите родительскую таблицу с помощью опции
CASCADE
:DROP TABLE books CASCADE;