Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/video/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Postgresql 如何使用postgres在表中的第二列或第三列之后添加新列?_Postgresql - Fatal编程技术网

Postgresql 如何使用postgres在表中的第二列或第三列之后添加新列?

Postgresql 如何使用postgres在表中的第二列或第三列之后添加新列?,postgresql,Postgresql,如何使用postgres在表中的第二列或第三列之后添加新列 我的代码如下所示 ALTER TABLE n_domains ADD COLUMN contract_nr int after owner_id 不,没有直接的方法。这是有原因的——每个查询都应该以它需要的顺序(和格式等)列出它需要的所有字段,从而使一个表中列的顺序变得无关紧要 如果您确实需要这样做,我可以想出一个解决方法: 转储并保存相关表的描述(使用pg_dump--schema only--table=…) 将所需列添加到保存

如何使用postgres在表中的第二列或第三列之后添加新列

我的代码如下所示

ALTER TABLE n_domains ADD COLUMN contract_nr int after owner_id

不,没有直接的方法。这是有原因的——每个查询都应该以它需要的顺序(和格式等)列出它需要的所有字段,从而使一个表中列的顺序变得无关紧要

如果您确实需要这样做,我可以想出一个解决方法:

  • 转储并保存相关表的描述(使用
    pg_dump--schema only--table=…
  • 将所需列添加到保存的定义中所需的位置
  • 在保存的定义中重命名表,以便在尝试创建时不会与旧表的名称冲突
  • 使用此定义创建新表
  • 使用“插入到
    选择字段1,字段2,
    ,字段3,…”用旧表中的数据填充新表,。。。从
    '
  • 重命名旧表
  • 将新表重命名为原始名称
  • 在确保一切正常后,最终放弃旧的、重新命名的表

列的顺序在关系数据库中是完全无关的

例如,如果您使用Python,您将执行以下操作:

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 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

列的顺序并不无关,将固定宽度的列放在表的前面可以优化数据的存储布局,还可以在应用程序代码之外更轻松地处理数据

PostgreSQL不支持更改列顺序(请参见PostgreSQL wiki上的);如果该表是相对独立的,最好是重新创建该表:

创建表foobar_new(…);
插入到foobar_新建选择。。。来自foobar;
升降台foobar级联;
将表foobar\u新重命名为foobar;

如果表中定义了大量视图或约束,则可以在新列之后重新添加所有列,并删除原始列(请参见PostgreSQL wiki的示例)。

@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)
正如我在上面对peufeu回复的评论中所指出的那样,当你的遗产没有做到这一点时,问题就来了

更新:我突然想到,通过在SELECT子句中指定列名,您可以对INSERT子句中的列名执行相同的操作。您只需将它们重新排序以匹配目标表中的序号:

INSERT INTO test2 SELECT three, two, one FROM test1;
当然,你可以做到两个都非常明确:

INSERT INTO test2 (one, two, three) SELECT one, two, three FROM test1;
这将得到与上面相同的结果,列值正确匹配。

@Milen A.Radev

获取列的查询并不总是定义与列的设置顺序无关的需求。在
pg_fetch_row
的值中,不包括关联的列名,因此需要由SQL语句定义列

一个简单的
select*from
将需要表结构的固有知识,如果列的顺序发生变化,有时会导致问题


使用
pg_fetch_assoc
是一种更可靠的方法,因为您可以引用列名,因此使用一个简单的
select*from

这里真正的问题是它还没有完成。目前PostgreSQL的逻辑顺序与物理顺序相同。这是一个问题,因为您无法获得不同的逻辑l排序,但更糟糕的是,表不是自动物理打包的,因此通过移动列可以获得不同的性能特征

争辩说设计中的意图是这样的是毫无意义的。当提交一个可接受的补丁时,它很可能会在某个时候发生变化

综上所述,依靠逻辑或物理列的顺序定位是一个好主意吗?绝对不是。在生产代码中,您永远不应该使用隐式排序或
*
。为什么要使代码比需要的更脆弱?正确性应该始终比节省几次击键更重要

作为一种解决方法,您实际上可以通过

另见

  • 重新排序以提高空间效率

列顺序与我有关,因此我创建了此函数。请查看它是否有帮助。它与索引、主键和触发器一起工作。缺少视图、外键和其他功能

例如:

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;
CREATE或REPLACE函数xaddcolumn(ptable text、pcol text、pafter text)将void作为$BODY返回$
声明
rcol记录;
rkey记录;
ridx记录;
rtgr记录;
vsql文本;
vkey文本;
视频文本;
cidx文本;
vtgr文本;
ctgr文本;
etgr文本;
vseq文本;
vtype文本;
vcols文本;
开始
执行“创建表格zzz”| | ptable | |作为SELECT*FROM'| | ptable;
--科鲁纳斯
vseq='';
vcols='';
vsql=‘创建表’| | ptable | |’(’;
对于rcol,选择列\u name作为col,udt\u name作为coltype,列\u default作为coldef,
可为空,字符的最大长度为len,
数值精度为num prec,数值刻度为num刻度
从信息_schema.columns
其中table_name=ptable
按序号位置排序
环
vtype=rcol.coltype;
如果(substr(rcol.coldef,1,7)='nextval'),则
vtype='串行';
vse