Несмотря на возможность включения новых полей в существующую таблицу, следует помнить, что в PostgreSQL не поддерживается удаление полей. Существует два относительно простых способа реструктуризации существующих таблиц. Первый способ основан на использовании команды CREATE TABLE A, а во втором способе команда CREATE TABLE объединяется с командой INSERT INTO.
Фактически оба способа сводятся к созданию новой таблицы требуемой структуры, заполнению ее данными из существующей таблицы и переименованию. Таким образом, новая таблица занимает место старой.
Внимание! При реструктуризации таблиц следует помнить, что идентификаторы объектов (OID) изменятся, а старые индексы, сгенерированные для исходной таблицы, не будут автоматически действовать в новых таблицах. Все индексы необходимо удалить и построить заново.
CREATE TABLE ASРаспространенная методика реструктуризации таблиц основана на использовании команды CREATE TABLE с секцией AS в сочетании с запросом SQL. Команда создает временную таблицу на основании существующей таблицы, после чего временная таблица переименовывается. Физическое создание новой таблицы может сопровождаться удалением полей и изменением порядка их следования с одновременным заполнением данными из исходной таблицы.
В приведенном ниже описании синтаксиса этой усеченной версии команды CREATE TABLE запрос представляет собой команду SELECT для выборки данных, переносимых в новую таблицу. Типы данных всех создаваемых полей определяются типами данных соответствующих полей, выбранных в результате выполнения запроса.
CREATE [ TEMPORARY | TEMP ] TABLE таблица [ (имя_поля [….])] AS запросПреимущество такого подхода заключается в том, что создание таблицы и заполнение ее данными происходит в одной команде SQL. Самый заметный недостаток – отсутствие полноценных возможностей для установки ограничений в созданной таблице. После того как таблица создана, в нее можно добавлять только ограничения внешних ключей и проверки. После создания новой таблицы старую таблицу можно переименовать (или уничтожить) и присвоить новой таблице имя старой.
Допустим, из таблицы books удаляется лишнее поле publication, созданное ранее. Для этого мы создаем усеченную версию таблицы (с перечислением нужных полей) с указанием соответствующей команды SELECT в секции AS команды CREATE TABLE, после чего старая таблица удаляется командой DROP TABLE (листинг 8).
Листинг 8. Реструктуризация таблицы командой CREATE TABLE AS.
booktown=# \d books
Table "books"
Attribute | Type | Modifier
id | integer | not null
title | text | not null
author_id | integer |
subject_id| integer |
publication | date |
Index: books_id_pkey
booktown=# CREATE TABLE new_books (id, title, author_id, subject_id) AS SELECT id, title, author_id, subject_id FROM books;
SELECT
booktown=# ALTER TABLE books RENAME TO old_books;
ALTER
booktown=# ALTER TABLE new_books RENAME TO books;
ALTER
booktown=# \d books
Table "books"
Attribute | Type | Modifier
id | integer |
title | text |
author_id | integer |
subject_id| integer |
booktown=# DROP TABLE books;
DROPВнимание пользователям старых версий! В версии PostgreSQL 7.1.x присутствие в команде SELECT необязательного списка полей, заключенного в круглые скобки, исключает использование специального символа *.
Если таблица, создаваемая командой CREATE TABLE AS, вас почему-либо не устраивает (например, если в таблице необходимо установить ограничения полей), то одну команду CREATE TABLE AS можно заменить двумя командами SQL. Сначала команда CREATE TABLE создает новую таблицу, а затем команда INSERT INTO с запросом SELECT заполняет ее данными (листинг 9).
Листинг 9. Реструктуризация таблицы командами CREATE TABLE и INSERT INTO.
booktown=# CREATE TABLE new_books (id integer UNIQUE, title text NOT NULL, author_id integer, subject_id integer, CONSTRAINT books_id_pkey PRIMARY КЕУ (id);
NOTICE: CREATE TABLE/PRIMARY KEY will create implicit index 'books_id_pkey'
for table 'new_books'
CREATE
booktown=# INSERT INTO new_books SELECT id, title, author_id, subject_id FROM books;
INSERT 0 12
booktown=# ALTER TABLE books RENAME TO old_books;
ALTER
booktown=# ALTER TABLE new_books RENAME TO books:
ALTER
booktown=# \d books
Table "books"
Attribute | Type | Modifier
id | integer | not null
title | text | not null
author_id |integer |
subject_id integer |
Index: books_id_pkeyDROP TABLEВ SQL таблицы удаляются командой DROP TABLE. Команда имеет следующий синтаксис (таблица – имя удаляемой таблицы):
DROP TABLE таблица
Использование команды DROP TABLE требует осторожности, поскольку удаление таблицы приводит к уничтожению всех хранящихся в ней данных.
Примечание. Уничтожение таблицы с неявно созданным индексом приводит к уничтожению всех связанных с ней индексов.
После создания таблицы с заданной структурой наступает следующий этап – заполнение таблицы данными. В PostgreSQL имеются три общих способа заполнения таблиц данными:
INSERT INTO;
INSERT INTO в сочетании с командой SELECT;
Ниже приведен синтаксис команды INSERT INTO при вставке новых данных:
INSERT INTO таблица
[ (имя_поля [,…]) ] VALUES (значение [….])Ниже перечислены параметры команды.
таблица. Имя таблицы, в которую вставляются данные командой SQL INSERT.
(имя_поля [….]). Необязательный группированный список полей новой записи, которым присваиваются значения.
VALUES. Ключевое слово SQL, за которым следует группированный список значений.
(значение [,… ]). Обязательный группированный список значений полей. Для каждого поля указывается ровно одно значение, элементы списка разделяются запятыми. Элемент списка может быть выражением (например, операцией с двумя операндами) или константой.
Тип каждого значения в секции VALUES должен соответствовать типу поля, которому оно присваивается. Если необязательный список полей отсутствует, PostgreSQL предполагает, что секция VALUES содержит значения всех полей в структуре таблицы в порядке их определения. Если количество значений меньше количества полей, PostgreSQL пытается использовать значение по умолчанию (или NULL при его отсутствии) для каждого пропущенного элемента.
В листинге 10 приведен пример создания новой записи в таблице books базы данных booktown.
Листинг 10. Вставка новой записи в таблицу books.
booktown=# INSERT INTO books (id, title, author_id, subject_id) VALUES (41472, 'Practical PostgreSQL', 1212, 432);
INSERT
3574037 1Команда SQL, приведенная в листинге 10, вставляет новую запись с кодом (id) 41472, названием “Practical PostgreSQL”, кодом автора 1212 и кодом темы 432. Обратите внимание на завершающее сообщение, начинающееся со слова INSERT, – оно указывает на то, что операция вставки была выполнена успешно. Первое число после INSERT является идентификатором объекта (OID) созданной записи, а второе число обозначает количество созданных записей (в нашем примере,– 1).
В приведенном примере необязательный список полей совпадает с порядком следования полей в структуре таблицы (слева направо). В данном случае этот список можно опустить, поскольку команда INSERT предполагает, что значения присваиваются в естественном порядке следования полей таблицы. Поля в списке можно переставить, но в этом случае порядок значений в секции VALUES тоже должен измениться, как показано в листинге 11.
Листинг 11. Изменение порядка перечисления полей.
INSERT INTO books (subjected, author_id, id, title) VALUES (4, 7805, 41473, 'Programming Python');
INSERT 3574041 1SELECTКоманда INSERT INTO применяется и в другой ситуации – когда данные, сохраняемые в таблице, уже присутствуют в другой таблице (или нескольких таблицах). В этом случае команда имеет следующий синтаксис:
INSERT INTO таблица
[ (имя_поля [….]) ] запросПо аналогии с синтаксисом INSERT INTO, команда содержит необязательный список полей, которым присваиваются новые значение. Тем не менее в этой форме INSERT INTO секция VALUES заменяется полной командой SQL SELECT.
Предположим, база данных booktown содержит таблицу book_queue с информацией о книгах, ожидающих поступления в продажу. После подтверждения данные переносятся из таблицы book_queue в обычную таблицу books. Пример решения этой задачи продемонстрирован в листинге 12.
Листинг 12. Вставка данных из другой таблицы.
INSERT INTO books (id, title, author_id, subject_id) SELECT nextval('book_ids'), title, author_id, subject_id FROM book_queue WHERE approved;
INSERT 0 2В приведенном примере запрос SELECT, включенный в команду INSERT INTO, переносит две записи из таблицы book_queue в таблицу books. В этом контексте допускается использование любой синтаксически правильной команды SELECT. В нашем примере в выборку включается результат вызова функции nextval () для последовательности book_ids, за которым следуют значения полей title, author_id и subject_id из таблицы book_queue.
На этот раз команда создает сразу несколько новых записей, поэтому в сообщении об успешном выполнении операции вместо значения OID, которое выводилось бы при вставке одной записи, выводится 0. Второе число, как и в случае с обычной командой INSERT INTO, равно количеству созданных записей (в данном случае – 2).
| Модификация таблицы командой ALTER TABLE | Выборка данных командой SELECT |