我在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”值。如果没有,我应该如何解决这个问题?
答案 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>
,则需要开始输入列名称。