将 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 文件加载到配置单元表时未选择行

将CSV加载到BigQuery表中的问题

通过验证将 csv 文件内容加载到 mysql 表中

Hive:将hdfs中的gziped CSV作为只读加载到表中

将多个 CSV 文件加载到 MYSQL 中的单个表中 [重复]

将大型 CSV 文件加载到核心数据中的最快方法是啥