2014-12-04 67 views
0

我试图在具有多个列的架构中通过索引命名来创建新表。通过postgresql中的循环添加多列

CREATE TABLE rflux (pk SERIAL PRIMARY KEY NOT NULL); 

现在我想添加新的列像col0 FLOAT,col1,col2,col3 ....直到colN。

我知道我可以这样做

ALTER TABLE rflux add column col0 FLOAT add column col1 FLOAT ... ; 

,但我不想一切都打出来,因为我需要创建〜4500列。我试图用循环来实现这一点,但我无法完成它的工作。有没有人有任何想法?我试图创建一个函数来做到这一点..

create function addColumns() 
returns void 
as $$ 
begin 
for i in 1..10 loop 
alter table rflux add column tmp float; 
alter table rflux rename tmp to col||i; 
end loop; 
return; 
end; 
$$ 
language plpgsql; 

然后做 SELECT * FROM addColumns();

但是,当将列重命名为col || i时,或甚至当我尝试i时,我都会遇到错误。我甚至不确定这是否是最好的方法。如何添加多列,以便我可以使用计数器增加列的名称?

编辑..我知道我不能用4500列做这个,但是如果我想为10列做这个问题,这个问题有什么解决方法呢?

谢谢。

+0

[每表250的最大列 - 1600根据列类型](http://www.postgresql.org/about/) – 2014-12-04 16:31:16

+0

4500列?我想你可能会考虑重新设计你的模式,而不是把你的糟糕设计带入数据库。然而,要做你想做的事,你需要在一个存储过程中使用“动态SQL”......但你可能不应该这样做。 – JNevill 2014-12-04 16:41:03

+0

我真正想要的是以某种方式将4500个元素的数组存储到数据库中。我可以将它作为一个float []存储为一列,或者每个元素都是一个单独的列。我关心访问,并通过SQLAlchemy切片数组。据我所知,postgres将数组存储为字符串元素{1,2,3}。当它被SQLAlchemy读入时,它解析这个字符串并将其转换为元素列表。我将拥有数百万行数据,并且需要过滤行的子集,其中某些数组元素满足给定的条件。所以我认为第二种方式会更好。 – havok2063 2014-12-04 18:34:22

回答

0

您的设计可能更适合数组,hstore或json数据类型。添加4500列是等待发生的噩梦。

+0

是的,这听起来很像,特别是考虑到postgresql中的列限制。你知道这是如何影响在SQLalchemy中甚至在Postgres中为数百万行进行这些数组的子集上的过滤效率? – havok2063 2014-12-04 19:23:15

+0

如果你使用的是postgres 9.3,json非常好,你甚至可以索引json对象中的单个数据元素。 如果您使用的版本低于9.3,我会使用hstore并且这些子字段也可以被索引。 有了一个数组,你就失去了命名字段的能力,订单变得非常重要,所以我个人会避免这种情况。 – 2014-12-04 21:01:21

+0

嗯。好。我使用的是postgres 9.3,所以我会考虑使用JSON和hstore。我不太了解他们与数组相比,但如果他们让我轻松地选择查询列中的元素的子集,那么我就是为了它。谢谢。 – havok2063 2014-12-04 23:50:38

0

如果它可以帮助:

-- VERSION : POSTGRESQL 9.3 

-- FICTIVE TABLE #1 

CREATE TABLE table_1 ("YEAR" int, "CODE_SP" text, "TOTAL" int); 

INSERT INTO table_1 VALUES 
(2035, 'TRUC', 2), 
(2035, 'MUCH', 4), 
(2036, 'FLIC', 7), 
(2036, 'LORD', 2), 
(2036, 'TRUC', 8), 
(2037, 'MUCH', 2), 
(2037, 'FLIC', 2), 
(2037, 'FLAC', 5), 
(2037, 'MORD', 9), 
(2038, 'LOOP', 3), 
(2038, 'MUCH', 3); 

SELECT * FROM table_1; 

-- FICTIVE TABLE #2 

CREATE TABLE table_2 ("YEAR" int); 

INSERT INTO table_2("YEAR") 
SELECT serial 
FROM generate_series(2035,2038,1) AS serial; 

SELECT * FROM table_2; 

-- LOOP FOR ADDING COLUMNS ON TABLE #2 

DO 
$do$ 
    DECLARE colnames TEXT; 
BEGIN 
FOR colnames IN 
    SELECT "CODE_SP" 
    FROM table_1 
    GROUP BY "CODE_SP" 
    ORDER BY "CODE_SP" 
LOOP 
    EXECUTE 'ALTER TABLE table_2 ADD COLUMN ' || quote_ident(colnames) || ' INT DEFAULT NULL;'; /* careful: in quoted text, the spaces are important */ 
END LOOP; 
END 
$do$; 

-- LOOP FOR COMPLETTING CELLS ON TABLE #2 

DO 
$do$ 
    DECLARE id_value TEXT; 
BEGIN 
FOR id_value IN 
    SELECT "CODE_SP" 
    FROM table_1 
    GROUP BY "CODE_SP" 
    ORDER BY "CODE_SP" 
LOOP 
    EXECUTE 'UPDATE table_2 SET ' || quote_ident(id_value) || ' = table_1."TOTAL" FROM table_1 WHERE table_1."CODE_SP" = ' || quote_literal(id_value) || ' AND table_1."YEAR" = table_2."YEAR";'; /* careful: in quoted text, the spaces are important */ 
END LOOP; 
END 
$do$;