如何使用添加的列从csv复制到Postgres表中?

时间:2019-03-21 12:20:35

标签: postgresql copy

我在Postgres中有一个表,我想从一个copy into文件中csv。我通常这样做:

\copy my_table from '/workdir/some_file.txt' with null as 'NULL' delimiter E'|' csv header;

但是,现在的问题是my_table多了一列,我想手动在copy上填写相同的值'b'。这是我的桌子:

some_file.txt:
col1 | col2 | col3
  0     0      1
  0     1      3

my_table :
xtra_col | col1 | col2 | col3
   a        5      2       5
   a        6      2       5
   a        7      2       5

Desired my_table after copy into:
xtra_col | col1 | col2 | col3
   a        5      2       5
   a        6      2       5
   a        7      2       5
   b        0      0       1
   b        0      1       3

有没有一种方法可以在复制语句中为“ xtra_col”列提及持久的“ b”值。如果没有,我应该如何解决这个问题?

2 个答案:

答案 0 :(得分:2)

您可以为xtra_col设置(临时)默认值:

ALTER TABLE my_table ALTER COLUMN xtra_col SET DEFAULT 'b';
COPY my_table (col1, col2, col3) FROM '/workdir/some_file.txt' WITH (FORMAT CSV, DELIMITER '|', NULL 'NULL', HEADER true);
ALTER TABLE my_table ALTER COLUMN xtra_col DROP DEFAULT;

  

有没有一种方法可以不重复my_table中的列?真正的my_table有20列,我不想调用所有这些列。

如果my_table有很多列,而您希望避免键入所有列名, 您可以像这样动态生成COPY命令:

SELECT format($$COPY my_table(%s) FROM '/workdir/some_file.txt' WITH (FORMAT CSV, DELIMITER '|', NULL 'NULL', HEADER true);$$
              , string_agg(quote_ident(attname), ','))
FROM   pg_attribute
WHERE attrelid = 'my_table'::regclass
    AND attname != 'xtra_col'
    AND attnum > 0

然后您可以复制并粘贴SQL来运行它。


或者,对于完全免提的操作,您可以创建一个函数来生成SQL并执行它:

CREATE OR REPLACE FUNCTION test_func(filepath text, xcol text, fillval text)
RETURNS void
LANGUAGE plpgsql
AS $func$
DECLARE sql text;
BEGIN
  EXECUTE format($$ALTER TABLE my_table ALTER COLUMN %s SET DEFAULT '%s';$$, xcol, fillval);

  SELECT format($$COPY my_table(%s) FROM '%s' WITH (FORMAT CSV, DELIMITER '|', NULL 'NULL', HEADER true);$$
        , string_agg(quote_ident(attname), ','), filepath)
  INTO sql
  FROM   pg_attribute
  WHERE attrelid = 'my_table'::regclass
      AND attname != 'xtra_col'
      AND attnum > 0;
  EXECUTE sql;

  EXECUTE format($$ALTER TABLE my_table ALTER COLUMN %s DROP DEFAULT;$$, xcol);
END;
$func$;

SELECT test_func('/workdir/some_file.txt', 'xtra_col', 'b');

这是我用来测试上述解决方案的sql:

DROP TABLE IF EXISTS test;
CREATE TABLE test (
    xtra_col text
    , col1 int
    , col2 int
    , col3 int
);
INSERT INTO test VALUES
('a', 5, 2, 5)
, ('a', 6, 2, 5)
, ('a', 7, 2, 5);

/ tmp / data的内容为

col1 | col2 | col3
  0  |   0  |   1
  0  |   1  |   3

然后

SELECT test_func('/tmp/data', 'xtra_col', 'b');
SELECT * FROM test;

产生

+----------+------+------+------+
| xtra_col | col1 | col2 | col3 |
+----------+------+------+------+
| a        |    5 |    2 |    5 |
| a        |    6 |    2 |    5 |
| a        |    7 |    2 |    5 |
| b        |    0 |    0 |    1 |
| b        |    0 |    1 |    3 |
+----------+------+------+------+
(5 rows)

关于pg.dropped列:

至少在上面使用的test_func表上,pg.dropped调用似乎没有产生test列:

unutbu=# SELECT *
    FROM pg_attribute
    WHERE attrelid = 'test'::regclass;

+----------+----------+----------+---------------+--------+--------+----------+-------------+-----------+----------+------------+----------+------------+-----------+-------------+--------------+------------+-------------+--------------+--------+------------+---------------+
| attrelid | attname  | atttypid | attstattarget | attlen | attnum | attndims | attcacheoff | atttypmod | attbyval | attstorage | attalign | attnotnull | atthasdef | attidentity | attisdropped | attislocal | attinhcount | attcollation | attacl | attoptions | attfdwoptions |
+----------+----------+----------+---------------+--------+--------+----------+-------------+-----------+----------+------------+----------+------------+-----------+-------------+--------------+------------+-------------+--------------+--------+------------+---------------+
|    53393 | tableoid |       26 |             0 |      4 |     -7 |        0 |          -1 |        -1 | t        | p          | i        | t          | f         |             | f            | t          |           0 |            0 |        |            |               |
|    53393 | cmax     |       29 |             0 |      4 |     -6 |        0 |          -1 |        -1 | t        | p          | i        | t          | f         |             | f            | t          |           0 |            0 |        |            |               |
|    53393 | xmax     |       28 |             0 |      4 |     -5 |        0 |          -1 |        -1 | t        | p          | i        | t          | f         |             | f            | t          |           0 |            0 |        |            |               |
|    53393 | cmin     |       29 |             0 |      4 |     -4 |        0 |          -1 |        -1 | t        | p          | i        | t          | f         |             | f            | t          |           0 |            0 |        |            |               |
|    53393 | xmin     |       28 |             0 |      4 |     -3 |        0 |          -1 |        -1 | t        | p          | i        | t          | f         |             | f            | t          |           0 |            0 |        |            |               |
|    53393 | ctid     |       27 |             0 |      6 |     -1 |        0 |          -1 |        -1 | f        | p          | s        | t          | f         |             | f            | t          |           0 |            0 |        |            |               |
|    53393 | xtra_col |       25 |            -1 |     -1 |      1 |        0 |          -1 |        -1 | f        | x          | i        | f          | f         |             | f            | t          |           0 |          100 |        |            |               |
|    53393 | col1     |       23 |            -1 |      4 |      2 |        0 |          -1 |        -1 | t        | p          | i        | f          | f         |             | f            | t          |           0 |            0 |        |            |               |
|    53393 | col2     |       23 |            -1 |      4 |      3 |        0 |          -1 |        -1 | t        | p          | i        | f          | f         |             | f            | t          |           0 |            0 |        |            |               |
|    53393 | col3     |       23 |            -1 |      4 |      4 |        0 |          -1 |        -1 | t        | p          | i        | f          | f         |             | f            | t          |           0 |            0 |        |            |               |
+----------+----------+----------+---------------+--------+--------+----------+-------------+-----------+----------+------------+----------+------------+-----------+-------------+--------------+------------+-------------+--------------+--------+------------+---------------+
(10 rows)

据我所知,当删除列时,pg.dropped列为a natural result of how PostgreSQL works。因此,无需修复。 attname包含pg.dropped的行也带有负数attnum

这就是在attnum > 0中使用test_func的原因-从生成的列名列表中删除此类行。

我对Postgresql的经验有限,所以我可能是错的。如果您可以生成一个示例,该示例生成带有正pg.dropped的{​​{1}}“列”,那么我非常希望看到它。

答案 1 :(得分:2)

我通常将文件加载到临时表中,然后从那里插入(或更新)。在这种情况下,

CREATE TEMP TABLE input (LIKE my_table);
ALTER TABLE input DROP xtra_col;

\copy input from 'some_file.txt' ...

INSERT INTO my_table
SELECT 'b', * FROM input;

INSERT语句看起来很整洁,但是只有当要排除的列位于my_table的任一端时,才能真正实现。在您的(可能是简化的)示例中,xtra_col位于最前面,因此我们可以使用*快速添加其余的列。

如果CSV文件列的排列方式与my_table的差异远远超过<style style="text/css"> .scroll-slow { height: 20px; overflow: hidden; position: relative; background: gray; color: white; border: 1px solid gray; } .scroll-slow p { position: absolute; width: 100%; height: 100%; margin: 0; line-height: 20px; text-align: center; /* Starting position */ -moz-transform:translateX(100%); -webkit-transform:translateX(100%); transform:translateX(100%); /* Apply animation to this element */ -moz-animation: scroll-slow 25s linear infinite; -webkit-animation: scroll-slow 25s linear infinite; animation: scroll-slow 25s linear infinite; } /* Move it (define the animation) */ @-moz-keyframes scroll-slow { 0% { -moz-transform: translateX(100%); } 100% { -moz-transform: translateX(-100%); } } @-webkit-keyframes scroll-slow { 0% { -webkit-transform: translateX(100%); } 100% { -webkit-transform: translateX(-100%); } } @keyframes scroll-slow { 0% { -moz-transform: translateX(100%); /* Browser bug fix */ -webkit-transform: translateX(100%); /* Browser bug fix */ transform: translateX(100%); } 100% { -moz-transform: translateX(-100%); /* Browser bug fix */ -webkit-transform: translateX(-100%); /* Browser bug fix */ transform: translateX(-100%); } } </style> <!DOCTYPE html> <html> <body> <div class="scroll-slow"> <?php $myfile = fopen("d:\file.txt", "r") or die("Unable to open file!"); echo fgets($myfile); fclose($myfile); ?> </div> </body> </html> ,则需要开始输入列名称。