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

问题描述 投票:8回答:4

我正在尝试编写一个脚本,将交叉表查询中的数据复制到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文件?

postgresql csv crosstab
4个回答
5
投票

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;

12
投票

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

来自psql manpage的相关摘录补充说:

元命令

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

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

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

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


0
投票

根据psql documentation

-f文件名

--file filename

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

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

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

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


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
© www.soinside.com 2019 - 2024. All rights reserved.