我正在运行一个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
答案 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
也没关系。 ; - )