将列表传递给PSQL中的环境变量

时间:2016-08-09 18:33:09

标签: sql bash shell psql

在线程here之后:我使用psql变量创建了以下SQL脚本:

--query.sql
select * from my_table 
where day=:'day' and state in (:'states')

我在脚本中使用以下shell命令通过SSH执行上述SQL脚本:

#!/bin/sh
day='2015-05-01'
state='CA'
ssh myserver "psql -A -q -F $'\t' -d my_db -o temp_file.csv --set=day=${day} --set=states=${state}" < 'query.sql'

我遇到的问题是如何传递状态列表。如果我想从shell脚本传递3个状态,如:

state="'CA','NY','WA'"

我的数据库查询将返回0行。将状态列表从shell脚本传递到psql变量的正确方法是什么?

1 个答案:

答案 0 :(得分:1)

问题似乎不在shell中,而是在SQL中:

state in (:'states')

在大多数SQL品种中 - 以及包含Postgres的AFAIK--变量是标量。它包含单个值,而不是列(当然不是行)。你想要一个列表,但在SQL中没有这样的动物。用

初始化时
state="'CA','NY','WA'"

你提供的字符串看起来有点像列表。然而,SQL并没有被愚弄:它期望一个标量和口香糖就是它所看到的。由于没有具有该名称的状态,因此它返回零行。

  

传递状态列表的正确方法是什么

有三种常见的答案:糟糕的方式,好的方式和正确的方式。

  • 不安全的方法是动态构造IN子句。

  • 标准答案是将值作为列提供。您可能拥有表值变量或临时表。将状态名称插入一个,并执行类似

  • 的操作

where state in ('select state from #states')

  • 如果这看起来很迂回,那么正确的答案可能在于数据库本身。考虑:状态列表是任意,还是它们有共同点?可以从数据库中的数据生成看似随意的列表吗?如果它们属于某个已知区域,或者处于某种支持下,或者是某些先前历史的产物,则可能应该在数据库中表示。如果是,则问题从提供列表转换为生成它。您的查询变为

where state in ('select state from ... where ... = :criterion)

虽然我从未见过明确的理由,但我怀疑SQL中没有很好地支持任意列表,因为它们通常可以而且应该通过设计来避免。