如何在PostgreSQL中的表中第二或第三列后添加新列?
我的代码如下所示:
ALTER TABLE n_domains ADD COLUMN contract_nr int after owner_id
如何在PostgreSQL中的表中第二或第三列后添加新列?
我的代码如下所示:
ALTER TABLE n_domains ADD COLUMN contract_nr int after owner_id
不,没有直接的方法可以实现这个功能。这是有原因的——每个查询都应该按照所需的顺序列出所有需要的字段(以及格式等),从而使得表中列的顺序变得无关紧要。
如果你确实需要这样做,我可以想到一个解决方法:
pg_dump --schema-only --table=<schema.table> ...
将相关表的描述信息进行导出并保存<new_table>
SELECT field1, field2, <default_for_new_field>
, field3,... FROM <old_table>
’将旧表中的数据填充到新表中CREATE TABLE foobar_new ( ... );
INSERT INTO foobar_new SELECT ... FROM foobar;
DROP TABLE foobar CASCADE;
ALTER TABLE foobar_new RENAME TO foobar;
如果您的表中定义了许多视图或约束条件,可以在新列之后重新添加所有列,然后删除原始列(请参阅PostgreSQL维基百科上的示例)。
*
。为什么要让代码变得比必须的更脆弱呢?正确性应该始终比节省一些按键次数更重要。对于我来说,列的顺序很重要,因此我创建了这个函数。看看它是否有帮助。它适用于索引、主键和触发器。缺少视图、外键和其他功能。
示例:
SELECT xaddcolumn('table', 'col3 int NOT NULL DEFAULT 0', 'col2');
源代码:
CREATE OR REPLACE FUNCTION xaddcolumn(ptable text, pcol text, pafter text) RETURNS void AS $BODY$
DECLARE
rcol RECORD;
rkey RECORD;
ridx RECORD;
rtgr RECORD;
vsql text;
vkey text;
vidx text;
cidx text;
vtgr text;
ctgr text;
etgr text;
vseq text;
vtype text;
vcols text;
BEGIN
EXECUTE 'CREATE TABLE zzz_' || ptable || ' AS SELECT * FROM ' || ptable;
--colunas
vseq = '';
vcols = '';
vsql = 'CREATE TABLE ' || ptable || '(';
FOR rcol IN SELECT column_name as col, udt_name as coltype, column_default as coldef,
is_nullable as is_null, character_maximum_length as len,
numeric_precision as num_prec, numeric_scale as num_scale
FROM information_schema.columns
WHERE table_name = ptable
ORDER BY ordinal_position
LOOP
vtype = rcol.coltype;
IF (substr(rcol.coldef,1,7) = 'nextval') THEN
vtype = 'serial';
vseq = vseq || 'SELECT setval(''' || ptable || '_' || rcol.col || '_seq'''
|| ', max(' || rcol.col || ')) FROM ' || ptable || ';';
ELSIF (vtype = 'bpchar') THEN
vtype = 'char';
END IF;
vsql = vsql || E'\n' || rcol.col || ' ' || vtype;
IF (vtype in ('varchar', 'char')) THEN
vsql = vsql || '(' || rcol.len || ')';
ELSIF (vtype = 'numeric') THEN
vsql = vsql || '(' || rcol.num_prec || ',' || rcol.num_scale || ')';
END IF;
IF (rcol.is_null = 'NO') THEN
vsql = vsql || ' NOT NULL';
END IF;
IF (rcol.coldef <> '' AND vtype <> 'serial') THEN
vsql = vsql || ' DEFAULT ' || rcol.coldef;
END IF;
vsql = vsql || E',';
vcols = vcols || rcol.col || ',';
--
IF (rcol.col = pafter) THEN
vsql = vsql || E'\n' || pcol || ',';
END IF;
END LOOP;
vcols = substr(vcols,1,length(vcols)-1);
--keys
vkey = '';
FOR rkey IN SELECT constraint_name as name, column_name as col
FROM information_schema.key_column_usage
WHERE table_name = ptable
LOOP
IF (vkey = '') THEN
vkey = E'\nCONSTRAINT ' || rkey.name || ' PRIMARY KEY (';
END IF;
vkey = vkey || rkey.col || ',';
END LOOP;
IF (vkey <> '') THEN
vsql = vsql || substr(vkey,1,length(vkey)-1) || ') ';
END IF;
vsql = substr(vsql,1,length(vsql)-1) || ') WITHOUT OIDS';
--index
vidx = '';
cidx = '';
FOR ridx IN SELECT s.indexrelname as nome, a.attname as col
FROM pg_index i LEFT JOIN pg_class c ON c.oid = i.indrelid
LEFT JOIN pg_attribute a ON a.attrelid = c.oid AND a.attnum = ANY(i.indkey)
LEFT JOIN pg_stat_user_indexes s USING (indexrelid)
WHERE c.relname = ptable AND i.indisunique != 't' AND i.indisprimary != 't'
ORDER BY s.indexrelname
LOOP
IF (ridx.nome <> cidx) THEN
IF (vidx <> '') THEN
vidx = substr(vidx,1,length(vidx)-1) || ');';
END IF;
cidx = ridx.nome;
vidx = vidx || E'\nCREATE INDEX ' || cidx || ' ON ' || ptable || ' (';
END IF;
vidx = vidx || ridx.col || ',';
END LOOP;
IF (vidx <> '') THEN
vidx = substr(vidx,1,length(vidx)-1) || ')';
END IF;
--trigger
vtgr = '';
ctgr = '';
etgr = '';
FOR rtgr IN SELECT trigger_name as nome, event_manipulation as eve,
action_statement as act, condition_timing as cond
FROM information_schema.triggers
WHERE event_object_table = ptable
LOOP
IF (rtgr.nome <> ctgr) THEN
IF (vtgr <> '') THEN
vtgr = replace(vtgr, '_@eve_', substr(etgr,1,length(etgr)-3));
END IF;
etgr = '';
ctgr = rtgr.nome;
vtgr = vtgr || 'CREATE TRIGGER ' || ctgr || ' ' || rtgr.cond || ' _@eve_ '
|| 'ON ' || ptable || ' FOR EACH ROW ' || rtgr.act || ';';
END IF;
etgr = etgr || rtgr.eve || ' OR ';
END LOOP;
IF (vtgr <> '') THEN
vtgr = replace(vtgr, '_@eve_', substr(etgr,1,length(etgr)-3));
END IF;
--exclui velha e cria nova
EXECUTE 'DROP TABLE ' || ptable;
IF (EXISTS (SELECT sequence_name FROM information_schema.sequences
WHERE sequence_name = ptable||'_id_seq'))
THEN
EXECUTE 'DROP SEQUENCE '||ptable||'_id_seq';
END IF;
EXECUTE vsql;
--dados na nova
EXECUTE 'INSERT INTO ' || ptable || '(' || vcols || ')' ||
E'\nSELECT ' || vcols || ' FROM zzz_' || ptable;
EXECUTE vseq;
EXECUTE vidx;
EXECUTE vtgr;
EXECUTE 'DROP TABLE zzz_' || ptable;
END;
$BODY$ LANGUAGE plpgsql VOLATILE COST 100;
rtgr
中删除了, condition_timing as cond
和vtgr
中的|| ' ' || rtgr.cond
添加了|| ' CASCADE'
以处理在EXECUTE 'DROP TABLE ' || ptable;
上链接的表顺便说一句,这个好用的函数似乎只能处理小写列名... - Jiab77@Jeremy Gustie的解决方案基本上是可行的,但如果序数不正确(或者重新排序的序数使不兼容的类型匹配失败),它将执行错误操作。试一试:
CREATE TABLE test1 (one varchar, two varchar, three varchar);
CREATE TABLE test2 (three varchar, two varchar, one varchar);
INSERT INTO test1 (one, two, three) VALUES ('one', 'two', 'three');
INSERT INTO test2 SELECT * FROM test1;
SELECT * FROM test2;
结果显示问题:
testdb=> select * from test2;
three | two | one
-------+-----+-------
one | two | three
(1 row)
INSERT INTO test2 (one, two, three) SELECT * FROM test1;
这将给你真正想要的东西:
testdb=> select * from test2;
three | two | one
-------+-----+-----
three | two | one
(1 row)
INSERT INTO test2 SELECT three, two, one FROM test1;
当然,你可以同时进行两种方式以使得非常明确:
INSERT INTO test2 (one, two, three) SELECT one, two, three FROM test1;
这将给你与上述相同的结果,其中列值正确匹配。
cursor.execute( "SELECT id, name FROM users" )
for id, name in cursor:
print id, name
或者你可以这样做:
cursor.execute( "SELECT * FROM users" )
for row in cursor:
print row['id'], row['name']
但是没有理智的人会像这样使用位置结果:
cursor.execute( "SELECT * FROM users" )
for id, name in cursor:
print id, name
peufeu
所说的。 - Evan Carroll嗯,这对于数据库管理员来说是一个视觉上的好东西,并且可以在引擎中实现,只会有轻微的性能损失。将列顺序表添加到pg_catalog
或最适合的位置。将其保留在内存中,并在某些查询之前使用它。为什么要过度思考这样一个小的视觉效果。
@ Milen A. Radev
有时候,需要按照一定的列顺序排列并不是由检索它们的查询所定义的。在从pg_fetch_row
返回的值中,不包括相关的列名,因此需要通过SQL语句来定义列。
一个简单的select * from
需要对表结构有内在的了解,并且如果列的顺序发生变化,有时会导致问题。
使用pg_fetch_assoc
是一种更可靠的方法,因为您可以引用列名,因此可以使用简单的select * from
。
SELECT *
,但我希望更有趣的列能够排在前面。 - maaartinus