Можно ли изменить естественный порядок столбцов в Postgres?
-
02-07-2019 - |
Вопрос
Можно ли изменить естественный порядок столбцов в Postgres 8.1?
Я знаю, что вам не следует полагаться на порядок столбцов - это не существенный к тому, что я делаю - мне это нужно только для того, чтобы некоторые автоматически сгенерированные данные отображались более приятным образом, чтобы порядок полей совпадал на всем пути от pgadmin до серверной части и далее до передней части.
Решение
На самом деле вы можете просто изменить порядок столбцов, но я бы вряд ли рекомендовал это делать, и вам следует быть очень осторожным, если вы решите это сделать.
например.
# CREATE TABLE test (a int, b int, c int); # INSERT INTO test VALUES (1,2,3); # SELECT * FROM test; a | b | c ---+---+--- 1 | 2 | 3 (1 row)
Теперь самое сложное: вам нужно подключиться к вашей базе данных с помощью пользователя postgres, чтобы вы могли изменять системные таблицы.
# SELECT relname, relfilenode FROM pg_class WHERE relname='test'; relname | relfilenode ---------+------------- test_t | 27666 (1 row) # SELECT attrelid, attname, attnum FROM pg_attribute WHERE attrelid=27666; attrelid | attname | attnum ----------+----------+-------- 27666 | tableoid | -7 27666 | cmax | -6 27666 | xmax | -5 27666 | cmin | -4 27666 | xmin | -3 27666 | ctid | -1 27666 | b | 1 27666 | a | 2 27666 | c | 3 (9 rows)
attnum - это уникальный столбец, поэтому вам нужно использовать временное значение при изменении номеров столбцов как таковых:
# UPDATE pg_attribute SET attnum=4 WHERE attname='a' AND attrelid=27666; UPDATE 1 # UPDATE pg_attribute SET attnum=1 WHERE attname='b' AND attrelid=27666; UPDATE 1 # UPDATE pg_attribute SET attnum=2 WHERE attname='a' AND attrelid=27666; UPDATE 1 # SELECT * FROM test; b | a | c ---+---+--- 1 | 2 | 3 (1 row)
Опять же, поскольку это игра с системными таблицами базы данных, будьте предельно осторожны, если вы чувствуете, что вам действительно нужно это сделать.
Это работает начиная с postgres 8.3, в предыдущих версиях ваш пробег может отличаться.
Другие советы
Если ваша база данных не очень большая и вы можете позволить себе некоторое время простоя, то вы можете:
- Отключить доступ на запись к базе данных
это важно, так как в противном случае любые изменения после запуска следующего пункта будут потеряны pg_dump --create --column-inserts databasename > databasename.pgdump.sql
- Редактировать уместно
CREATE TABLE
оператор в databasename.pgdump.sql
Если файл слишком велик для вашего редактора, просто разделите его с помощьюsplit
командуйте, редактируйте, затем соберите обратно, используяcat
drop database databasename
У вас ведь есть недавняя резервная копия, на всякий случай, не так ли?psql --single-transaction -f databasename.pgdump.sql
Если вы не используете--single-transaction
это будет очень медленно
Если вы используете так называемые большие объекты, убедитесь, что они включены в дамп.Я не уверен, установлены ли они по умолчанию в 8.1.
Я задавал этот вопрос в pgsql-admin в 2007 году.Сам Том Лейн заявил, что изменить порядок в каталогах практически невозможно.
Разъяснение:для пользователей, с имеющимися инструментами.Это не значит, что это не могло быть реализовано.ИМО, так и должно быть.
По-прежнему актуально для Postgres 11.
Как упоминалось в других ответах, вы не можете изменить порядок столбцов, это зависит от postgres.Вы можете (и должны!) решить свою проблему с помощью view.Для целей вашего запроса отчета это будет выглядеть точно так же, как таблица.Что -то вроде:
create view my_view as
select * from my_table
order by some_col;
Указание порядка столбцов в запросе - единственный надежный (и разумный) способ.Тем не менее, обычно вы можете получить другой порядок, изменив таблицу, как показано в примере ниже, поскольку столбцы обычно (не гарантируется) возвращаются в том порядке, в котором они были добавлены в таблицу.
postgres=# create table a(a int, b int, c int);
CREATE TABLE
postgres=# insert into a values (1,2,3);
INSERT 0 1
postgres=# select * from a;
a | b | c
---+---+---
1 | 2 | 3
(1 row)
postgres=# alter table a add column a2 int;
ALTER TABLE
postgres=# select * from a;
a | b | c | a2
---+---+---+----
1 | 2 | 3 |
(1 row)
postgres=# update a set a2 = a;
UPDATE 1
postgres=# alter table a drop column a;
ALTER TABLE
postgres=# alter table a rename column a2 to a;
ALTER TABLE
postgres=# select * from a;
b | c | a
---+---+---
2 | 3 | 1
(1 row)
postgres=#
К сожалению, нет, это не так.Порядок столбцов полностью зависит от Postgres.
Вы можете получить желаемый порядок столбцов, создав новую таблицу и выбрав столбцы старой таблицы в том порядке, в котором вы хотите, чтобы они были представлены:
CREATE TABLE test_new AS SELECT b, c, a FROM test;
SELECT * from test_new;
b | c | a
---+---+---
2 | 3 | 1
(1 row)
Обратите внимание, что при этом копируются только данные, а не модификаторы, ограничения, индексы и т.д..
Как только новая таблица будет изменена так, как вы хотите, удалите оригинал и измените имя новой:
BEGIN;
DROP TABLE test;
ALTER TABLE test_new RENAME TO test;
COMMIT;
Я хочу того же.Да, заказать это сейчас необходимо, но это просто сбивает меня с толку :)
Что я делаю, чтобы решить эту проблему, заключается в следующем.
Этот метод гарантирует, что вы СОХРАНИТЕ все существующие данные,
- Создайте новую версию таблицы, используя нужный мне порядок, используя временное имя.
- Вставьте в эту новую таблицу все данные из существующей.
- Отбросьте старую таблицу.
- Переименуйте новую таблицу в "собственное имя" из "временного имени".
- Повторно добавьте все индексы, которые у вас были ранее.
- Сбросьте последовательность идентификаторов для приращений первичного ключа.
Текущий порядок расположения столов:
id, name, email
1.Создайте новую версию таблицы, используя нужный мне порядок, используя временное имя.
В этом примере я хочу email
быть до того, как name
.
CREATE TABLE mytable_tmp
(
id SERIAL PRIMARY KEY,
email text,
name text
);
2.Вставьте в эту новую таблицу все данные из существующей.
INSERT INTO mytable_tmp --- << new tmp table
(
id
, email
, name
)
SELECT
id
, email
, name
FROM mytable; --- << this is the existing table
3.Отбросьте старую таблицу.
DROP TABLE mytable;
4.Переименуйте новую таблицу в "собственное имя" из "временного имени".
ALTER TABLE mytable_tmp RENAME TO mytable;
5.Повторно добавьте все индексы, которые у вас были ранее.
CREATE INDEX ...
6.Сбросьте последовательность идентификаторов для приращений первичного ключа.
SELECT setval('public.mytable_id_seq', max(id)) FROM mytable;