请耐心等待,因为这是我的第一篇文章。
我正在尝试在PostgreSQL-9.2中运行COPY命令,将.txt文件中的制表符分隔表添加到PostgreSQL数据库,例如:
COPY raw_data FROM '/home/Projects/TestData/raw_data.txt' WITH (DELIMITER ' ');
我已经使用SQL命令在数据库中创建了一个名为“raw_data”的空表:
CREATE TABLE raw_data ();
尝试运行COPY
命令时,我一直收到以下错误消息:
ERROR: extra data after last expected column
CONTEXT: COPY raw_data, line 1: " 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 ..."
(这里的数字应该是列标题)
我不确定是否因为我在创建db表时没有指定表列,但我试图避免手动输入800或列。
有关如何解决此问题的任何建议吗?
以下是.txt文件的示例:
1 2 3 4 5 6 7 8 9
binary1 1 1 0 1 1 1 1 1 1
binary2 1 0 0 1 0 1 1 0 0
binary3 1 0 1 1 1 0 0 1 0
binary4 1 1 1 1 0 1 0 1 0
答案 0 :(得分:11)
空表不行。您需要与输入数据结构匹配的表。类似的东西:
CREATE TABLE raw_data (
col1 int
, col2 int
...
);
您无需将tab
声明为DELIMITER
,因为这是默认设置:
COPY raw_data FROM '/home/Projects/TestData/raw_data.txt';
你说的800列吗?许多列通常表明您的设计存在问题。无论如何,有一些方法可以使CREATE TABLE
脚本自动化一半。
假设简化原始数据
1 2 3 4 -- first row contains "column names"
1 1 0 1 -- tab separated
1 0 0 1
1 0 1 1
定义不同的DELIMITER
(根本不会出现在导入数据中),并导入到具有单个text
列的临时登台表:
CREATE TEMP TABLE tmp_data (raw text);
COPY tmp_data FROM '/home/Projects/TestData/raw_data.txt' WITH (DELIMITER '§');
此查询创建CREATE TABLE
脚本:
SELECT 'CREATE TABLE tbl (col' || replace (raw, E'\t', ' bool, col') || ' bool)'
FROM (SELECT raw FROM tmp_data LIMIT 1) t;
更通用的&更安全的查询:
SELECT 'CREATE TABLE tbl('
|| string_agg(quote_ident('col' || col), ' bool, ' ORDER BY ord)
|| ' bool);'
FROM (SELECT raw FROM tmp_data LIMIT 1) t
, unnest(string_to_array(t.raw, E'\t')) WITH ORDINALITY c(col, ord);
返回:
CREATE TABLE tbl (col1 bool, col2 bool, col3 bool, col4 bool);
验证有效性后执行 - 如果您信任结果,则动态执行:
DO
$$BEGIN
EXECUTE (
SELECT 'CREATE TABLE tbl (col' || replace(raw, ' ', ' bool, col') || ' bool)'
FROM (SELECT raw FROM tmp_data LIMIT 1) t
);
END$$;
然后使用此查询INSERT
数据:
INSERT INTO tbl
SELECT (('(' || replace(replace(replace(
raw
, '1', 't')
, '0', 'f')
, E'\t', ',')
|| ')')::tbl).*
FROM (SELECT raw FROM tmp_data OFFSET 1) t;
使用translate()
更简单:
INSERT INTO tbl
SELECT (('(' || translate(raw, E'10\t', 'tf,') || ')')::tbl).*
FROM (SELECT raw FROM tmp_data OFFSET 1) t;
将字符串转换为行文字,转换为新创建的表格行类型并使用(row).*
进行分解。
全部完成。
您可以将所有这些放入plpgsql函数中,但是您需要防止SQL注入。 (这里有很多相关的解决方案。请尝试搜索。
db<>小提琴here
Old SQL Fiddle
答案 1 :(得分:1)
您可以直接从copy命令创建表,查看COPY中的HEADER选项,如: 复制来自'/path/to/csv/SourceCSVFile.csv'DELIMITERS','CSV HEADER