Наследование

Наследование позволяет создавать дочерние таблицы, которые получают описания столбцов из родительской таблицы.

Например, нужно создать следующие таблицы:

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;
Нашли ошибку? Выделите текст и нажмите Ctrl+Enter чтобы сообщить о ней