【问题标题】:PostgreSQL: How to pass parameters from command line?PostgreSQL:如何从命令行传递参数?
【发布时间】:2011-09-12 14:24:58
【问题描述】:

我在使用? 占位符的脚本中有一个比较详细的查询。我想直接从 psql 命令行(在脚本之外)测试这个相同的查询。我想避免进入并用实际值替换所有?,而是想在查询之后传递参数。

例子:

SELECT  * 
FROM    foobar
WHERE   foo = ?
   AND  bar = ?
    OR  baz = ?  ;

寻找类似的东西:

%> {select * from foobar where foo=? and bar=? or baz=? , 'foo','bar','baz' };

【问题讨论】:

  • 请提供更多上下文。此查询是在 SQL 文件中、在 Perl/Python/Ruby/ 脚本中还是在其他地方?
  • @Jack:我希望直接从 psql 提示符(命令行)执行此操作。我正在从脚本中获取我的代码,但不想经历整个查找/替换过程。
  • @Vol7ron,请在下面查看我的答案以获取 psql 命令行示例。
  • @MAbraham1:很好。我应该为我的问题提供更多背景信息。我有很多在开放文本中包含 SQL 的脚本。有时,使用自定义值将其直接针对数据库进行调试很有用。我正在寻找一种在 Postgres 中轻松完成此操作而无需保存其他文件的方法。
  • @Vol7ron,谢谢。我在考虑批处理作业,但是您也应该能够在开放 SQL 中使用令牌。如果您喜欢我的回答,请不要忘记投票。

标签: postgresql parameters


【解决方案1】:

您可以使用 -v 构造,例如

psql -v v1=12  -v v2="'Hello World'" -v v3="'2010-11-12'"

然后将sql中的变量称为:v1,:v2等

select * from table_1 where id = :v1;

请注意我们如何使用两个引号" '...' "传递字符串/日期值

【讨论】:

  • +1 有趣,传递命名参数。登录后您知道有什么方法可以做到这一点吗?
  • 当然,只需使用\set v3 'another value'。请记住,当您需要在 SQL 语句中引用值时,请在变量名周围使用撇号,例如:SELECT * FROM foo WHERE bar = :'v3';
  • 我猜他们是从awk那里得到的
  • 可以用@代替:像sqlserver
  • 注意,在阅读本文后,我希望发现使用 -v 设置的变量可用于使用 -c 执行的命令,但可惜它们不是。换句话说,psql -v v1=12 -v v2="'Hello World'" -v v3="'2010-11-12'" -c 'select * from table_1 where id = :v1;' 会产生语法错误。但是,如果 bash 是您的 shell,您可以尝试:psql -v v1=12 -v v2="'Hello World'" -v v3="'2010-11-12'" <<< 'select * from table_1 where id = :v1;' 效果很好。
【解决方案2】:

在 PostgreSQL 中发现,您可以 PREPARE statements 就像在脚本语言中一样。不幸的是,您仍然不能使用?,但您可以使用$n 表示法。

使用上面的例子:

PREPARE foo(text,text,text) AS
    SELECT  * 
    FROM    foobar
    WHERE   foo = $1
       AND  bar = $2
        OR  baz = $3  ;
EXECUTE foo('foo','bar','baz');
DEALLOCATE foo;

【讨论】:

  • @IvanBlack 您还打算包含其他内容吗? :) 在会话结束时自动执行释放
  • 请注意,现在foo 很忙,另一个PREPARE 应该有另一个名称,而当前会话没有关闭。如果您将PREPARE 与psql 一起玩,那么每次都很难发明一个新名称,DEALLOCATE 可以提供帮助 =)
  • IMO 这个解决方案非常好。一个有用的副作用 - 您可以轻松地多次调用准备好的语句。
【解决方案3】:

在psql中有一个机制通过

\set name val

command,它应该与-v name=val 命令行选项相关联。引用很痛苦,在大多数情况下,将整个查询肉放在一个 shell here-document 中会更容易。

编辑

哎呀,我应该说-v 而不是-P(用于格式化选项)之前的回复是正确的。

【讨论】:

    【解决方案4】:

    您也可以在 psql 命令行或批处理文件中传入参数。第一个语句收集连接到数据库所需的详细信息。

    最后的提示要求输入约束值,它将在 WHERE 列 IN() 子句中使用。记住要单引号 if 字符串,并用逗号分隔:

    @echo off
    echo "Test for Passing Params to PGSQL"
    SET server=localhost
    SET /P server="Server [%server%]: "
    
    SET database=amedatamodel
    SET /P database="Database [%database%]: "
    
    SET port=5432
    SET /P port="Port [%port%]: "
    
    SET username=postgres
    SET /P username="Username [%username%]: "
    
    SET /P bunos="Enter multiple constraint values for IN clause [%constraints%]: "
    ECHO you typed %constraints%
    PAUSE
    REM pause
    "C:\Program Files\PostgreSQL\9.0\bin\psql.exe" -h %server% -U %username% -d %database% -p %port% -e -v v1=%constraints% -f test.sql
    

    现在在您的 SQL 代码文件中,在 WHERE 子句或 SQL 中的任何其他位置添加 v1 标记。请注意,标记也可以在打开的 SQL 语句中使用,而不仅仅是在文件中。将此另存为 test.sql:

    SELECT * FROM myTable
    WHERE NOT someColumn IN (:v1);
    

    在 Windows 中,将整个文件保存为 DOS BATch 文件 (.bat),将 test.sql 保存在同一目录中,然后启动批处理文件。

    感谢 EnterpriseDB 的 Dave Page 提供原始提示脚本。

    【讨论】:

    • +1 用于 Windows 示例;尽管大多数 Pg 数据库都存在于 *nix 变体中
    【解决方案5】:

    看来你问的can't be done directly from the command line。您要么必须在 plpgsql 中使用用户定义的函数,要么从脚本语言调用查询(后一种方法更容易避免 SQL 注入)。

    【讨论】:

      【解决方案6】:

      我想提供另一个受@malcook 评论启发的答案(使用 bash)。

      如果您需要在使用-c 标志时在查询中使用shell 变量,此选项可能对您有用。具体来说,我想获取一个表的计数,其名称是一个 shell 变量(使用 -c 时不能直接传递)。

      假设你有你的 shell 变量

      $TABLE_NAME='users'
      

      然后你可以通过使用得到结果

      psql -q -A -t -d databasename -c <<< echo "select count(*) from $TABLE_NAME;"
      

      (-q -A -t 只是打印出结果数字,无需额外格式化)

      我会注意到这里字符串中的echo(&lt;&lt;&lt; 运算符)可能不是必需的,我最初认为引号本身就可以了,也许有人可以澄清一下原因。

      【讨论】:

        【解决方案7】:

        我最终使用了更好版本的@vol7ron 答案:

        DO $$
        BEGIN
            IF NOT EXISTS(SELECT 1 FROM pg_prepared_statements WHERE name = 'foo') THEN
                PREPARE foo(text,text,text) AS
                    SELECT  * 
                    FROM    foobar
                    WHERE   foo = $1
                        AND bar = $2
                        OR  baz = $3;
            END IF;
        END$$;
        EXECUTE foo('foo','bar','baz');
        

        这样你总是可以按这个顺序执行它(只有当它还没有准备好时才准备好查询),重复执行并从最后一个查询中获取结果。

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 2011-09-28
          • 1970-01-01
          • 2016-03-25
          • 2011-09-10
          • 2012-07-26
          • 2018-09-02
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多