如何在PostgreSQL中复制多个CSV文件?

时间:2017-04-08 14:39:17

标签: postgresql csv postgis plpgsql postgresql-copy

我在Postgres有一个PostGIS数据库,我想将几​​个地理上不同的区域中的点提取到CSV文件,每个区域一个文件。

我已经设置了一个带有区域多边形和区域标题的area表格,我希望使用像Postgis这样的内容有效地遍历该表格。 st_intersects()选择要在每个CSV文件中输入的数据,并从区域表中的标题中获取CSV文件的文件名。

我对制作交叉点代码的详细信息以及设置CSV输出感到满意 - 我不知道的是如何为每个区域执行此操作。是否有可能通过某种联接来做这样的事情?或者我需要使用存储过程,并在plpgsql中使用循环结构?

2 个答案:

答案 0 :(得分:0)

您可以使用plpgsql函数或内联函数(如果您只需要执行一次,而不想存储函数。)

do $body$
  DECLARE i int;
  BEGIN FOR i IN SELECT DISTINCT city FROM table
    LOOP RAISE
      NOTICE 'foo';
      EXECUTE format($$COPY (SELECT * FROM foo WHERE x='%s') TO /tmp/%s$$, i, i); 
    END LOOP;
    RETURN;
  END;
$body$ LANGUAGE plpgsql;

答案 1 :(得分:0)

您可以在plpgsql中遍历区域表中的行。但要注意正确引用标识符和值:

假设这样设置:

CREATE TABLE area (
  title text PRIMARY KEY
, area_polygon geometry
); 

CREATE TABLE points(
  point_id serial PRIMARY KEY
, the_geom geometry); 

您可以使用此plpgsql块:

DO
$do$
DECLARE
   _title text;
BEGIN
   FOR _title IN
      SELECT title FROM area
   LOOP
      EXECUTE format('COPY (SELECT p.*
                            FROM   area   a
                            JOIN   points p ON ST_INTERSECTS(p.the_geom, a.area_polygon)
                            WHERE  a.title = %L) TO %L (FORMAT csv)'
                   , _title
                   , '/path/to/' || _title || '.csv');
   END LOOP;
END
$do$;

使用 %L 格式(对于字符串 l iteral)来获取正确引用的字符串,以避免语法错误和可能的 SQL注入。您仍然需要在area.title中使用适用于文件名的字符串。)

还要小心引用文件名作为一个整体,而不仅仅是它的标题部分。

注意表示"实用程序命令" COPY不允许使用INSERTUPDATEDELETE的DML命令中的变量替换。您必须将整个命令连接为 string

这就是我没有在循环中读出area.area_polygon的原因。我们必须将它转换为text以将其连接到查询字符串中,其中文本表示将被转换回geometry(或者您实际未公开的数据类型)。这很容易出错。

相反,我只读取area.title来唯一标识行并在内部处理查询中的其余部分。