Bash psql查询文件中是否可能出现换行?

Bash psql查询文件中是否可能出现换行?,bash,psql,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_q

我正在运行一个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

问题不在于查询文件中有换行符,而在于
\copy
元命令中有换行符。根据:

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

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

一种解决方法可能是,让您的
\copy
元命令运行一个只调用该函数的查询。

直接回答和解决方案 如中所述,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
CREATE TEMP TABLE ":table_name" AS
   [...query...]
\copy ":table_name" to 'ELA_comp_tot_daily_sess.csv' with CSV HEADER
<>你可能会考虑其他改进。

补充讨论 临时表的随机名称 您不太可能遇到表名冲突,但是,同样,通过创建一个随机名称来避免它们非常简单

SELECT 'tmp_' || (RANDOM()*1e15)::INT8 AS table_name
\gset
。。。用这个名字

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
CREATE TEMP TABLE ":table_name" AS
   [...query...]
\copy ":table_name" to 'ELA_comp_tot_daily_sess.csv' with CSV HEADER
请注意以下关于此处使用的psql特性的内容

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

  • 与所有的
    psql
    变量一样,由
    \gset
    创建的变量通过在变量名前加冒号来使用,如
    :table_name

  • RANDOM()…
    的值应
    CAST
    /转换为
    INT
    ,以消除任何小数点,这在未引用的表名中会很麻烦,甚至在引用时也可能会混淆。这里,我使用了一个
    BIGINT
    (或者别名
    INT8
    ),因为我要乘以的系数很大

尽管如此,您不太可能创建足够的临时表来创建冲突的名称

输出的动态文件名

只要使用<代码> \gSET/COD>创建表名,就可以考虑为输出创建动态文件名。

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
命令语法。使用较新的语法,它将如下所示:

\COPY ":table_name" TO ":file_name" WITH (FORMAT CSV, HEADER TRUE)
这是一个次要问题,因为9.x版仍然正式支持该语法。我喜欢大写
关键字也没关系