psql查询文件中的换行符可能吗?

时间:2016-01-20 04:18:02

标签: bash psql

我正在运行一个bash文件来处理一些psql任务。但是,我希望包含查询的文本文件(fp_query.txt)接受换行符以提高可读性。目前,我收到了这个错误:

parse error at end of line

我保持换行符。有没有办法让解释器忽略换行符,以便我可以将它们保存在查询文件中?

供参考,这是.sh文件:

export PGPASSFILE=.pgpass
psql -h [hostname] -d [dbname] -U [user] -f fp_query.txt

这是fp_query.txt:

\copy (SELECT created_at::date, COUNT(*)
    FROM ela_snapshots 
    WHERE created_at::date > CURRENT_DATE - 30 
    GROUP BY 1) to 'ELA_comp_tot_daily_sess.csv' with CSV HEADER

2 个答案:

答案 0 :(得分:3)

问题不在于您的查询文件中有换行符,而是在\copy元命令中有换行符。根据{{​​3}}:

  

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

(强调我的)。如果您在交互式psql提示符下运行此命令,则同样如此。

一种解决方法可能是the "Meta-Commands" section of the psql documentation for PostgreSQL 9.5,并让您的\copy元命令运行一个只调用该函数的查询。

答案 1 :(得分:2)

直接回答和解决方案

ruakh's answer所述,PostgreSQL元命令必须占用一行。我通过为\copy创建一个临时表来处理这个问题。

文件fp_query.txt的快速转换看起来像这样。

CREATE TEMP TABLE "temp_unique_name" AS
    SELECT created_at::date, COUNT(*)
    FROM ela_snapshots 
    WHERE created_at::date > CURRENT_DATE - 30 
    GROUP BY 1;
\copy "temp_uniq_name" to 'ELA_comp_tot_daily_sess.csv' with CSV HEADER

您可以考虑其他改进。

补充讨论

临时表的随机名称

您不太可能遇到表名冲突,但同样的,通过创建随机名称来避免它们非常简单......

SELECT 'tmp_' || (RANDOM()*1e15)::INT8 AS table_name
\gset

...并使用这样的名字。

CREATE TEMP TABLE ":table_name" AS
   [...query...]
\copy ":table_name" to 'ELA_comp_tot_daily_sess.csv' with CSV HEADER

请注意以下有关此处使用的psql功能的内容。

  • \gset元命令在缓冲区中运行查询,并将非空值设置为名为列别名的变量。有关详细信息,请查找\gset here重要,请注意查询以分号结尾,因为这会立即执行缓冲区!

  • 与所有psql变量一样,\gset创建的变量由预先挂起冒号到变量名称使用,如:table_name

  • RANDOM()...的值应为CAST /转换为INT以消除任何小数点,这在不带引号的表名中会很麻烦并且可能会造成混淆即使被引用。在这里,我使用BIGINT(或别名INT8),因为我乘以的因素很大。

所有这一切,你不可能创建足够的临时表来创建冲突的名称。

输出的动态文件名

只要您使用\gset创建表名,就可以考虑为输出创建动态文件名。

SELECT 'tmp_' || (RANDOM()*1e15)::INT8 AS table_name,
       'ELA_comp_tot_' || to_char(CURRENT_TIMESTAMP, 'YYYYMMDD_HHMMSS') || '.csv' AS file_name
\gset

现在,您可以使用以下内容。

\copy ":table_name" to ":file_name" with CSV HEADER

如上所述,这将输出到类似ELA_comp_tot_20180404_142329.csv的内容。顺便说一下,.csv扩展名不会改变输出,但更好地表示文件内容,特别是基于GUI的文件系统接口。

\copy元命令

的语法

您的示例代码(我已逐字复制以避免混淆)正在使用9.0版之前的COPY命令语法,如上所述here。使用较新的语法,它看起来像这样:

\COPY ":table_name" TO ":file_name" WITH (FORMAT CSV, HEADER TRUE)

这是一个小问题,因为版本9.x仍然正式支持语法。我喜欢利用KEYWORDS也没关系。 ; - )