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