Postgres:\ .sql文件中的复制语法错误

时间:2015-04-14 16:32:21

标签: postgresql csv crosstab

我试图编写一个脚本,将交叉表查询中的数据复制到Postgres 8.4中的.csv文件中。我能够在psql命令行中运行该命令但是当我将命令放在一个文件中并使用-f选项运行它时,我收到语法错误。

以下是我所看到的一个例子(来自this很棒的答案):

CREATE TEMP TABLE t (
  section   text
 ,status    text
 ,ct        integer 
);

INSERT INTO t VALUES
 ('A', 'Active', 1), ('A', 'Inactive', 2)
,('B', 'Active', 4), ('B', 'Inactive', 5)
                   , ('C', 'Inactive', 7);

\copy (
SELECT * FROM crosstab(
       'SELECT section, status, ct
        FROM   t
        ORDER  BY 1,2' 
       ,$$VALUES ('Active'::text), ('Inactive')$$)
AS ct ("Section" text, "Active" int, "Inactive" int)
) TO 'test.csv' HEADER CSV

然后我运行它并得到以下语法错误:

$ psql [system specific] -f copy_test.sql
CREATE TABLE
INSERT 0 5
psql:copy_test.sql:12: \copy: parse error at end of line
psql:copy_test.sql:19: ERROR:  syntax error at or near ")"
LINE 7: ) TO 'test.csv' HEADER CSV
        ^

类似的练习只做一个没有交叉表的简单查询,没有发生任何事故。

导致语法错误的原因是什么?如何使用脚本文件将此表复制到csv文件?

4 个答案:

答案 0 :(得分:11)

psql认为你的第一个命令只是\copy (而下面的行来自另一个不相关的语句。元命令不会在多行上传播,因为换行符是它们的终结符。

psql manpage的相关摘录补充说明:

  

元命令

     

您在psql中输入的任何以不带引号的反斜杠开头的内容都是   由psql本身处理的psql元命令。这些命令   使psql对管理或脚本更有用。元命令   通常称为斜杠或反斜杠命令   ....
  ....(跳过)

     

解析参数会在行尾或另一行停止   发现了未加引号的反斜杠。一个不带引号的反斜杠被视为   一个新的元命令的开头。特殊序列\\(两个   标记参数的结尾并继续解析SQL   命令,如果有的话。这样SQL和psql命令可以自由混合   在一条线上。 但无论如何,元命令的参数不能   继续超越行

所以第一个错误是\copy (失败,然后下面的行被解释为一个独立的SELECT,当有一个假的右括号时,它看起来很好,直到第7行。

正如评论中所说,修复方法是将整个元命令塞进一行。

答案 1 :(得分:4)

this answer一样,使用单行VIEW命令创建多行\copy,例如:

CREATE TEMP TABLE t (
  section   text
 ,status    text
 ,ct        integer 
);

INSERT INTO t VALUES
 ('A', 'Active', 1), ('A', 'Inactive', 2)
,('B', 'Active', 4), ('B', 'Inactive', 5)
                   , ('C', 'Inactive', 7);
CREATE TEMP VIEW v1 AS
  SELECT * FROM crosstab(
         'SELECT section, status, ct
          FROM   t
          ORDER  BY 1,2' 
         ,$$VALUES ('Active'::text), ('Inactive')$$)
  AS ct ("Section" text, "Active" int, "Inactive" int);

\copy (SELECT * FROM v1) TO 'test.csv' HEADER CSV

-- optional
DROP VIEW v1;

答案 2 :(得分:0)

根据psql documentation

  

-f filename

     

- 文件文件名

     

使用文件filename作为命令源,而不是以交互方式读取命令。处理完文件后,psql终止。这在很多方面等同于内部命令\ i。

     

如果filename是 - (连字符),则读取标准输入。

     

使用此选项与编写psql<略有不同文件名。一般来说,两者都可以达到您的预期,但使用-f可以启用一些不错的功能,例如带行号的错误消息。使用此选项也有可能减少启动开销。另一方面,使用shell的输入重定向的变体(理论上)保证产生与您手动输入所有内容完全相同的输出。

这将是-f选项以与命令行不同的方式处理您的输入的情况之一。删除你的新行有效,将原始文件重定向到psql的stdin可能也会有效。

答案 3 :(得分:0)

此处列出的答案非常清楚地解释了推理。这是一个小的hack,它允许你让你的sql包含多行并使用psql。

# Using a file
psql -f <(tr -d '\n' < ~/s/test.sql )
# or
psql < <(tr -d '\n' < ~/s/test.sql )

# Putting the SQL using a HEREDOC
cat <<SQL | tr -d '\n'  | \psql mydatabase
\COPY (
  SELECT
    provider_id,
    provider_name,
    ...
) TO './out.tsv' WITH( DELIMITER E'\t', NULL '', )
SQL