【问题标题】:Passing a list to an environment variable in PSQL将列表传递给 PSQL 中的环境变量
【发布时间】:2016-08-09 18:33:08
【问题描述】:

关注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 变量的正确方法是什么?

【问题讨论】:

    标签: sql bash shell psql


    【解决方案1】:

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

    state in (:'states')
    

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

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

    您正在提供一个看起来有点像列表的字符串。但是,SQL 并没有被愚弄:它需要一个标量,而这就是它所看到的。由于没有具有该名称的状态,因此它返回零行。

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

    有 3 个常见的答案:不好的方法、好的方法和正确的方法。

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

    • 标准答案是将值作为列提供。您可能会使用表值变量或临时表。将州名插入其中,然后执行类似

    • 的操作

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

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

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

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

    【讨论】:

    • 不幸的是,我会收到为状态组生成报告的请求,并且没有真正的统一标准。我很想只使用python,所以我可以只使用字符串工具来操作模板文件并插入state in ('CA','NY','WA')。
    • 是的,这是选项#1。根据您的环境,这对于安全性可能非常好,也可能是灾难性的。如果您可以控制 SQL 并审查州名,那我会这样做。否则,您将从小 Bobby Tables 进行 SQL 注入。 :-)
    猜你喜欢
    • 2020-03-08
    • 1970-01-01
    • 2013-12-29
    • 2021-09-05
    • 2020-03-27
    • 2017-03-30
    • 2018-08-19
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多