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

如何在PostgreSQL中复制到多个CSV文件?,postgresql,csv,postgis,plpgsql,postgresql-copy,Postgresql,Csv,Postgis,Plpgsql,Postgresql Copy,我有一个PostGIS数据库,里面有Postgres中的点,我想把几个地理位置不同的区域中的点提取到CSV文件中,每个区域一个文件 我已经设置了一个包含区域多边形和区域标题的区域表,我想有效地循环该表,使用类似Postgis的“st_intersects()来选择每个CSV文件中的数据,并从区域表中的标题获取CSV文件的文件名 我对做交叉点代码和设置CSV输出的细节很满意——我不知道如何为每个区域做。是否可以通过某种连接来执行类似的操作?或者我是否需要使用存储过程来执行此操作,并在plpgsql

我有一个PostGIS数据库,里面有Postgres中的点,我想把几个地理位置不同的区域中的点提取到CSV文件中,每个区域一个文件

我已经设置了一个包含区域多边形和区域标题的
区域
表,我想有效地循环该表,使用类似Postgis的“
st_intersects()
来选择每个CSV文件中的数据,并从区域表中的标题获取CSV文件的文件名


我对做交叉点代码和设置CSV输出的细节很满意——我不知道如何为每个区域做。是否可以通过某种连接来执行类似的操作?或者我是否需要使用存储过程来执行此操作,并在plpgsql中使用循环构造?

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


您可以在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
(用于字符串Literal)的格式来获取正确引用的字符串,以避免语法错误和可能的SQL注入。您仍然需要在
区域.title
中使用适用于文件名的字符串。)

还要注意引用整个文件名,而不仅仅是其中的标题部分

请注意“实用程序命令”
COPY
不允许变量替换,如DML命令中的
INSERT
UPDATE
DELETE
。必须将整个命令连接为字符串

这就是为什么我不读取循环中的
area.area\u polygon
。我们必须将其转换为
文本
,将其连接到查询字符串中,其中文本表示将转换回
几何体
(或任何实际未公开的数据类型)。这很容易出错

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


实际表格定义和您的Postgres版本将有助于澄清问题。
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$;