将 CSV 文件中的内容加载到 PostgreSQL 表中
Posted
技术标签:
【中文标题】将 CSV 文件中的内容加载到 PostgreSQL 表中【英文标题】:Load contents from a CSV file into a PostgreSQL table 【发布时间】:2013-04-27 12:12:40 【问题描述】:下面是我尝试将数据从文件加载到在 Linux RedHat 7.2 主机上运行的 PostgreSQL 8.0 数据库中所经历的过程的描述。
现在,我的问题是 FOR EVERY ROW
触发器被调用并且过程正在执行。
但是,我希望它在我输入文件名后检查表的相应行,并根据记录的内容决定是执行DUMP BULK DATA
还是 @ 987654323@ 仅一次(在触发器上)。
请帮我解决这个问题...
我的logfile.tmp
如下:
27/Apr/2013:17:03:42 +0530#192.168.1.3#16#0@#$http://localhost/images/
banner-left.jpg@#$10.1ff.ff.ff#-#Y#-
27/Apr/2013:17:03:42 +0530#192.168.1.3#16#0@#$http://localhost/images/
banner-left.jpg@#$10.ff.ff.2ff05#-#Y#-
我正在使用的 COPY 命令:
/usr/local/pgsql/bin/psql localhost -d d1 -U u1 -tc "COPY tblaccesslog ( accesstime, clientip, username, request,bytes, urlpath, url, contenttype, issite, webcatname) FROM 'logfile.tmp' WITH DELIMITER AS '#';" >> /tmp/parselog.log 2>&1
有问题的触发器 (insert_accesslog_trigger
):
insert_accesslog_trigger BEFORE INSERT ON tblaccesslog FOR EACH ROW EXECUTE PROCEDURE accesslog_insert_trigger()
最后是使用的触发函数(accesslog_insert_trigger()
):
accesslog_insert_trigger()
DECLARE
tablemaxtuples NUMERIC(10);
tableno NUMERIC(10);
newtable TEXT;
query TEXT;
tablecount NUMERIC(10);
min_limit NUMERIC(10);
max_limit NUMERIC(10);
BEGIN
tablemaxtuples := 100000;
tableno := ( NEW.id - ( NEW.id % tablemaxtuples ) ) / tablemaxtuples +1;
newtable := 'tblaccesslog'||to_char(CURRENT_DATE,'YYYYMMDD')||'_child_'||tableno;
SELECT trim(count(tablename)) INTO tablecount FROM pg_tables WHERE tablename=newtable ;
IF tablecount = 0
THEN
min_limit := (tableno-1)*tablemaxtuples;
max_limit := min_limit + tablemaxtuples;
query := 'CREATE TABLE '||newtable||'( PRIMARY KEY (id),CHECK ( id >= '||min_limit||' AND id <'||max_limit||' ) ) INHERITS (tblaccesslog)';
EXECUTE query;
END IF;
query := 'INSERT INTO '|| newtable ||' ( id, username, clientip, url, accesstime, requestbytes, contenttype, issite, urlpath, webcatname ) VALUES ('||NEW.id||','''||NEW.username||''','''||NEW.clientip||''','''||NEW.url||''','''||NEW.accesstime||''','''||NEW.requestbytes||''','''||NEW.contenttype||''','''||NEW.issite||''','''|| replace(NEW.urlpath,'\'','') ||''','''||NEW.webcatname||''')';
EXECUTE query;
RETURN NULL;
END;
【问题讨论】:
8.0 已经很老了,可能存在未修补的安全问题。请尽快升级。 Red Hat 7.2 更早(2001 年),可能存在更多安全问题。您应该尽快将此数据迁移到现代服务器。 我无法升级它们中的任何一个..由于某些原因..你能帮我只做这个配置吗? 【参考方案1】:PostgreSQL documentation overview of triggers 明确表明没有适合您要求的触发器类型:FOR EACH ROW
触发器,顾名思义,每行执行一次,并且如手册页所述“语句级触发器目前无法检查语句修改的各个行。"
但是,您可以将实际的 COPY
命令放入函数中。该函数可以COPY TO
一个临时表,然后执行适当的步骤来确定它应该从那里去哪里。
然后您的复制命令(我猜是在 cron
工作或类似工作中)将只运行 SELECT bulk_insert_access_log();
而不是当前列出的长行。
【讨论】:
这里我的问题是这个设置每次调用触发器都会占用过多的 CPU 资源。所以我只想减少它。只有当 CRON 调用要转储的新文件时才调用触发器。所以临时数据库不会解决我的问题。 触发器可以定义为在任何 INSERT、UPDATE 或 DELETE 操作之前或之后执行,每个修改的行执行一次,或“每个 SQL 语句”执行一次。在这个语句中它表明我可以用 SQL 调用来调用触发器......那么如何实现呢?我想做什么改变? 如果您使用为整个语句运行的触发器,您将无法访问插入的数据,正如我已经引用的那样。但是这个 has 根本没有理由成为触发器 - 只需编写一个自定义函数并从 cron 运行它。 是的,我认为它是更好的方法.. PSQL 中有什么方法可以让我知道哪个是最后更新的表吗?我想在哪个表中添加下一个即将到来的数据? 您可能会跟踪另一个表中使用的最后一个表 - 类似于select max(partition_no) + 1 from partitioned_table_info
...以上是关于将 CSV 文件中的内容加载到 PostgreSQL 表中的主要内容,如果未能解决你的问题,请参考以下文章
尝试将 hdfs 中的 csv 文件加载到配置单元表时未选择行
Hive:将hdfs中的gziped CSV作为只读加载到表中