无法在bash中循环遍历PostgreSQL查询导出的数组

时间:2018-05-19 18:04:05

标签: bash postgresql

我有一个PostgreSQL查询,我希望通过循环为多个地理区域运行。我想使用数组中的元素来修改查询以及我将数据导出到的csv文件的名称。所以从本质上讲,我希望查询运行... cwa ='MFR'...并导出到hourly_MFR.csv,然后运行... cwa ='PQR'...并导出到hourly_PQR.csv,等等。

这是我到目前为止所拥有的。我想也许脚本中的EOF可能会导致问题,但我无法弄清楚如何在保持脚本的一般格式的同时让循环工作。

此外,没有循环(不包括declare,for,do,done语句)的查询/脚本工作正常。

dbname="XXX"

username="XXXXX"

psql $dbname $username << EOF

declare -a arr=('MFR', 'PQR', 'REV')

for i in "${arr[@]}"

do

\COPY
(SELECT d.woyhh,
      COALESCE(ct.ct, 0) AS total_count
FROM
 (SELECT f_woyhh(d::TIMESTAMP) AS woyhh
  FROM generate_series(TIMESTAMP '2018-01-01', TIMESTAMP '2018-12-31', interval '1 hour') d) d
LEFT JOIN
 (SELECT f_woyhh((TIME)::TIMESTAMP) AS woyhh,
         count(*) AS ct
  FROM counties c
  JOIN ltg_data d ON ST_contains(c.the_geom, d.ltg_geom)
  WHERE cwa = $i
  GROUP BY 1) ct USING (whh)
ORDER BY 1) TO /var/www/html/GIS/ltg_db/bigquery/hourly_$i.csv CSV HEADER;

done

EOF

感谢您的帮助!

2 个答案:

答案 0 :(得分:2)

我认为你差点就在那里,你只需重新排序一些行。试试这个:

// BAD: but not sure a better way
switch reflect.TypeOf(remoteAddr).String() {
case "*net.UDPAddr":
    p.SrcIP = remoteAddr.(*net.UDPAddr).IP.String()
    p.SrcPort = uint(remoteAddr.(*net.UDPAddr).Port)
    p.DstPort = uint(localAddr.(*net.UDPAddr).Port)
case "*net.TCPAddr":
    p.SrcIP = remoteAddr.(*net.TCPAddr).IP.String()
    p.SrcPort = uint(remoteAddr.(*net.TCPAddr).Port)
    p.DstPort = uint(localAddr.(*net.TCPAddr).Port)
}

dbname="XXX" username="XXXXX" declare -a arr=('MFR', 'PQR', 'REV') for i in "${arr[@]}" do psql $dbname $username << EOF \COPY (SELECT d.woyhh, COALESCE(ct.ct, 0) AS total_count FROM (SELECT f_woyhh(d::TIMESTAMP) AS woyhh FROM generate_series(TIMESTAMP '2018-01-01', TIMESTAMP '2018-12-31', interval '1 hour') d) d LEFT JOIN (SELECT f_woyhh((TIME)::TIMESTAMP) AS woyhh, count(*) AS ct FROM counties c JOIN ltg_data d ON ST_contains(c.the_geom, d.ltg_geom) WHERE cwa = $i GROUP BY 1) ct USING (whh) ORDER BY 1) TO /var/www/html/GIS/ltg_db/bigquery/hourly_$i.csv CSV HEADER; EOF done declare循环是bash脚本的一部分,而for<<EOF之间的所有内容都是Postgresql查询的一部分。

答案 1 :(得分:1)

@Lienhart Woitok上面的答案中,解决方案肯定会奏效。但是 - 请注意,这会产生执行新的&#39; psql&#39;的副作用。呼叫,数据库连接设置,身份验证和后续响应返回;然后关闭连接 - 对于循环的每次迭代。

在这种情况下,您只运行循环的3次迭代,因此它可能不是一个重要问题。但是,如果扩展使用率以运行更多迭代,则可能需要优化此操作以仅运行单个数据库连接并批量查询它。

为此,可能需要使用临时工作文件来构建SQL命令。还有其他方法,但使用和调试相对简单:

QUERY_FILE=$(mktemp /tmp/query.XXXXXXX)

# note the use of an array isn't really necessary in this use
# case - and a simple set of values can be used equally as well
CWA="MFR PQR REV"

for i in $CWA
do
 cat <<EOF >> $QUERY_FILE
     <ADD_YOUR_QUERY_STATEMENTS_HERE>
EOF
done

psql --file=$QUERY_FILE $dbname $username

if (( $? )) 
then
  echo "query failed (QUERY_FILE: ($QUERY_FILE')"
  exit 1 
else
  echo "query succeeded"
  rm -f $QUERY_FILE
  exit 0
fi