2013-04-27 66 views
1

下面是我尝试将文件中的数据加载到运行在Linux RedHat 7.2主机上的PostgreSQL 8.0数据库中的过程的描述。将CSV文件中的内容加载到PostgreSQL表中

现在,我的问题是FOR EVERY ROW触发器正在调用并且该过程正在执行。

然而,我希望它做的事情是让它检查我的表的相应行,一旦我给出了文件名,并根据记录的内容决定是否仅执行DUMP BULK DATADUMP WHOLE CSV FILE一次(在触发器上)。

请帮我解决这个问题...

logfile.tmp如下:

27/Apr/2013:17:03:42 +0530#192.168.1.3#16#[email protected]#$http://localhost/images/ 
    [email protected]#$10.1ff.ff.ff#-#Y#- 
27/Apr/2013:17:03:42 +0530#192.168.1.3#16#[email protected]#$http://localhost/images/ 
    [email protected]#$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; 
+3

8.0很老了,可能还没有打补丁的安全问题。请尽快升级。 – 2013-04-28 06:42:37

+0

Red Hat 7.2甚至更老(2001年),可能会有更多的安全问题。您应该尽快将此数据迁移到现代服务器。 – 2013-04-28 21:44:09

+0

我无法升级其中的任何一个人。由于某些原因,只有您可以帮助我完成此配置吗? – 2013-04-29 05:08:02

回答

2

PostgreSQL documentation overview of triggers明确表示没有触发类型适合你的要求:FOR EACH ROW触发将一如它的名字一样,可以一次执行每行以及手册页状态“语句级触发器目前没有任何方法来检查由语句修改的单个行。”

但是,您可以改为将实际的COPY命令放入函数中。该功能可以将COPY TO作为一个临时表,然后执行相应的步骤以确定应从哪里开始。

然后你的复制命令(我猜测是在cron作业或类似的)只会运行SELECT bulk_insert_access_log();而不是当前列出的长行。

+0

这里我的问题是在这个设置中,每次调用触发器都会消耗太多的CPU资源。所以我只想减少它。只有在CRON调用新文件进行转储时才会触发调用。所以临时数据库不能解决我的问题。 – 2013-04-29 05:11:33

+0

可以将触发器定义为在执行任何INSERT,UPDATE或DELETE操作之前或之后执行,可以是每个修改的行执行一次,也可以执行一次“每个SQL语句”。在这个声明中它显示了我可以用SQL调用触发器...所以如何实现它?我想做什么改变? – 2013-04-29 05:15:59

+0

如果您使用为整个语句运行的触发器,则无法访问所插入的数据,正如我已经引用的那样。但是这个*没有任何理由成为触发器 - 只需编写一个自定义函数并从cron运行即可。 – IMSoP 2013-04-29 14:43:51

相关问题