PostgreSQL - \copy 命令

3

我尝试了上面的代码。我成功编译了它。但是,当我运行时,它给了我一个错误:

Exception in thread "main" org.postgresql.util.PSQLException: ERROR: syntax error at or near "\"
Position: 1

这表明我运行的查询是错误的:
字符串查询为:String query ="\\COPY tmp from 'E:\\load.csv' delimiter ',';"; 对于该查询,System.out.println 的输出为:query string: \COPY tmp from 'E:\load.csv' delimiter ','; 我在 PostgresSQL 客户端运行查询:\COPY tmp from 'E:\load.csv' delimiter ',';,它可以正常工作。发生了什么?
Class.forName (driver);
conn = DriverManager.getConnection(host+dbname,user,password);
stmt = (java.sql.Statement) conn.createStatement();

//
PreparedStatement prepareUpdater = null;

conn.setAutoCommit(false);

String query ="\\COPY tmp from 'E:\\load.csv' delimiter ',';";

System.out.print("query string: "+query);

System.out.println("Query:"+query);
prepareUpdater = conn.prepareStatement(query);
prepareUpdater.executeUpdate();
prepareUpdater.close();

命令是COPY,没有反斜杠。 - Sami Kuhmonen
我需要运行的实际命令是\COPY,如果我只输入COPY,则可以将.csv文件加载到表中 - 错误必须是超级用户。 - user1823924
2
\COPY 是 psql 的内部命令,不是 SQL 命令。只有 psql 能够理解它。 - Sami Kuhmonen
4个回答

2

PostgreSQL的COPY语句分为两种 - 服务器端的COPYpsql端的\copy。两种语句具有相同的语法和非常相似的行为。但是有一个重要的区别 - \copy与客户端文件系统一起工作,而COPY则与服务器端文件系统一起工作。在使用\copy时,不应将其作为服务器端SQL命令调用,而应直接从psql或某些bash脚本中使用。

服务器端的COPY用于大规模的导出/导入操作。当它与文件系统一起工作时,只能由拥有超级用户权限的用户使用。非特权用户必须使用stdinstdout目标,但应用程序必须支持COPY API

psql支持它 - 因此您可以使用它将某个表从一个表复制到另一个表:

psql -c "COPY mytab TO stdout" db1 | psql -c "COPY targettab FROM stdin" db2

对于Java环境,您需要使用一些支持,例如CopyManager。请参见如何使用JDBC将数据从文件复制到PostgreSQL? 使用COPY语句导入可以比使用INSERT语句快得多,但取决于一些额外的开销 - 在没有很多索引和慢触发器的简单表上,差异将会很大。如果您在表上有很多索引或较慢的触发器,则来自COPY的加速效果将是微不足道的。

这个问题显然是关于在Windows操作系统中使用Java工作的,所以使用psqlstdinstdout的示例是不相关的。 - Patrick
这个“非特权用户必须使用标准输入输出目标”非常有帮助,因为大多数文章只说需要超级用户权限。是否有任何官方文件关于此事?谢谢。 - Richard
1
@Richard https://www.postgresql.org/docs/current/sql-copy.html - Pavel Stehule
@PavelStehule 谢谢。复制此部分,希望它能帮助其他人。 命名文件或命令只允许数据库超级用户或被授予其中一个角色的用户执行COPY操作。...... 不要将 COPY 与 psql 指令 \copy 混淆。\copy 调用 COPY FROM STDIN 或 COPY TO STDOUT,然后将数据提取/存储在对 psql 客户端可访问的文件中。因此,在使用 \copy 时,文件的可访问性和访问权限取决于客户端而不是服务器。 - Richard

0

你应该使用 COPY 而不是 /COPY

字符串查询 = "COPY tmp from 'E://load.csv' delimiter ','";

这样就可以正常工作了。


0
感谢您的反馈。
我成功地使用CSVReader加载了*.csv文件。
我下载了CSVReader包并将其包含在我的代码中。
它正常工作。
 CsvReader products = new CsvReader("/tmp/ip2location/IP-COUNTRY-REGION-CITY-LATITUDE-LONGITUDE-ISP-DOMAIN-MOBILE-USAGETYPE.CSV");

             products.readHeaders();

             while (products.readRecord())
             {
                String ip_from = products.get("ip_from"); //int
                String ip_to = products.get("ip_to"); //int


                PreparedStatement prepareStat = null;

                String sqlIinsert = "insert into ip2location_tmp(ip_from, ip_to )"
        + " VALUES ("+ip_from+","+ip_to+");";

                System.out.println("sqlInsert:"+sqlIinsert);
                prepareStat = conn.prepareStatement(sqlIinsert); 
                prepareStat.executeUpdate();  

               }
        products.close();
        }enter code here

3
你对PreparedStatement的使用完全错误(并且低效)。你应该在while循环之前只准备一次,使用占位符。然后在循环内部使用setString()提供实际值,然后调用executeUpdate() - user330315

-2

COPY SQL命令从本地文件系统中读取文件,服务器进程必须能够访问该文件。

\copy 命令是一个psql指令,仅在该环境中可用。您不能在SQL查询中使用它。

由于Java有一个好的CSV reader类,因此您可以在代码中简单地读取文件,然后使用单个INSERT命令将数据加载到数据库中。这实际上就是在psql中工作时\copy所做的事情。


2
单独的INSERT操作比COPY慢得多。通常这取决于数据量大小,但对于大规模导入来说,这并不是一个好建议。 - Pavel Stehule
@PavelStehule 这是非常正确的,但并不是问题的解决方案。我在 OP 中没有看到任何暗示这可能是一个大型 CSV 文件。 - Patrick
我不同意句子“This is effectively what \copy does when working in psql” - 当然这取决于细节 - 但有点令人困惑。 - Pavel Stehule
另外,COPY 也支持向表中插入数据。请检查 COPY 表名 FROM '文件名'。 - frlan

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接