如何在 psql 中使用脚本变量?
在 MS SQL Server 中,我创建脚本来使用可自定义变量:
DECLARE @somevariable int
SELECT @somevariable = -1
INSERT INTO foo VALUES ( @somevariable )
然后,我将在运行时更改 @somevariable
的值,具体取决于特定情况下我想要的值。 由于它位于脚本的顶部,因此很容易看到和记住。
如何使用 PostgreSQL 客户端 psql
执行相同操作?
In MS SQL Server, I create my scripts to use customizable variables:
DECLARE @somevariable int
SELECT @somevariable = -1
INSERT INTO foo VALUES ( @somevariable )
I'll then change the value of @somevariable
at runtime, depending on the value that I want in the particular situation. Since it's at the top of the script it's easy to see and remember.
How do I do the same with the PostgreSQL client psql
?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(13)
postgres(自版本 9.0 起)允许使用任何受支持的服务器端脚本语言的匿名块
http://www.postgresql.org/docs/current/static/sql-do.html
由于所有内容都在字符串内,因此替换的外部字符串变量将需要转义并引用两次。 使用美元引用并不能提供针对 SQL 注入的全面保护。
postgres (since version 9.0) allows anonymous blocks in any of the supported server-side scripting languages
http://www.postgresql.org/docs/current/static/sql-do.html
As everything is inside a string, external string variables being substituted in will need to be escaped and quoted twice. Using dollar quoting instead will not give full protection against SQL injection.
您需要使用一种过程语言,例如 PL/pgSQL,而不是 SQL proc 语言。
在 PL/pgSQL 中,您可以直接在 SQL 语句中使用变量。
对于单引号,您可以使用引用文字函数。
You need to use one of the procedural languages such as PL/pgSQL not the SQL proc language.
In PL/pgSQL you can use vars right in SQL statements.
For single quotes you can use the quote literal function.
我用临时表解决了这个问题。
这样,我就有了一个可以在多个查询中使用的“变量”,该变量对于会话来说是唯一的。 我需要它生成唯一的“用户名”,同时在导入具有相同用户名的用户时仍然不会发生冲突。
I solved it with a temp table.
This way, I had a "variable" I could use over multiple queries, that is unique for the session. I needed it to generate unique "usernames" while still not having collisions if importing users with the same user name.
另一种方法是(ab)使用 PostgreSQL GUC 机制来创建变量。 有关详细信息和示例,请参阅之前的答案。
您在
postgresql.conf
中声明 GUC,然后在运行时使用SET
命令更改其值,并使用current_setting(...)
获取其值。我不建议将此用于一般用途,但它在狭窄的情况下可能很有用,例如链接问题中提到的情况,发布者想要一种为触发器和函数提供应用程序级用户名的方法。
Another approach is to (ab)use the PostgreSQL GUC mechanism to create variables. See this prior answer for details and examples.
You declare the GUC in
postgresql.conf
, then change its value at runtime withSET
commands and get its value withcurrent_setting(...)
.I don't recommend this for general use, but it could be useful in narrow cases like the one mentioned in the linked question, where the poster wanted a way to provide the application-level username to triggers and functions.
我真的很怀念这个功能。 实现类似功能的唯一方法是使用函数。
我以两种方式使用它:
Perl 版本:
表版本:
注意:
I really miss that feature. Only way to achieve something similar is to use functions.
I have used it in two ways:
Perl version:
Table version:
Notes:
psql
中的变量很糟糕。 如果要声明一个整数,则必须输入该整数,然后执行回车,然后以分号结束语句。 观察:假设我想声明一个整型变量
my_var
并将其插入到表test
中:示例表
test
:显然,其中没有任何内容表还:
我们声明一个变量。 注意下一行的分号!
现在我们可以插入了。 我们必须使用这种奇怪的“
:''
”语法:它有效!
解释:
那么...如果下一行没有分号会发生什么? 变量? 看一下:
我们声明了没有新行的
my_var
。让我们选择
my_var
。那是什么? 它不是一个整数,而是一个字符串
999;
!Variables in
psql
suck. If you want to declare an integer, you have to enter the integer, then do a carriage return, then end the statement in a semicolon. Observe:Let's say I want to declare an integer variable
my_var
and insert it into a tabletest
:Example table
test
:Clearly, nothing in this table yet:
We declare a variable. Notice how the semicolon is on the next line!
Now we can insert. We have to use this weird "
:''
" looking syntax:It worked!
Explanation:
So... what happens if we don't have the semicolon on the next line? The variable? Have a look:
We declare
my_var
without the new line.Let's select
my_var
.WTF is that? It's not an integer, it's a string
999;
!我为此发布了一个新的解决方案 在另一个线程上。
它使用表来存储变量,并且可以随时更新。 静态不可变 getter 函数是动态创建的(由另一个函数),由表更新触发。 您将获得良好的表存储,以及不可变 getter 的极快速度。
I've posted a new solution for this on another thread.
It uses a table to store variables, and can be updated at any time. A static immutable getter function is dynamically created (by another function), triggered by update to your table. You get nice table storage, plus the blazing fast speeds of an immutable getter.
我发现这个问题和答案非常有用,但也令人困惑。 我在让带引号的变量工作时遇到了很多麻烦,所以这是我让它工作的方法:
这样您就可以在一个语句中定义变量。 当您使用它时,单引号将嵌入到变量中。
笔记! 当我在引用的变量后面添加注释时,当我尝试其他答案中的某些方法时,它会作为变量的一部分被吸收。 这确实让我搞砸了一段时间。 使用此方法,注释似乎会按照您的预期进行处理。
I've found this question and the answers extremely useful, but also confusing. I had lots of trouble getting quoted variables to work, so here is the way I got it working:
This way you can define the variable in one statement. When you use it, single quotes will be embedded into the variable.
NOTE! When I put a comment after the quoted variable it got sucked in as part of the variable when I tried some of the methods in other answers. That was really screwing me up for a while. With this method comments appear to be treated as you'd expect.
FWIW,真正的问题是我在 \set 命令末尾包含了一个分号:
分号被解释为变量中的实际字符:
所以当我尝试使用它时:
...我懂了:
这不仅未能在文字周围设置引号,而且将命令分为两部分(第二部分无效,因为它以“NOINHERIT”开头)。
这个故事的寓意是:PostgreSQL“变量”实际上是文本扩展中使用的宏,而不是真正的值。 我确信这会派上用场,但一开始会很棘手。
FWIW, the real problem was that I had included a semicolon at the end of my \set command:
The semicolon was interpreted as an actual character in the variable:
So when I tried to use it:
...I got this:
That not only failed to set the quotes around the literal, but split the command into 2 parts (the second of which was invalid as it started with "NOINHERIT").
The moral of this story: PostgreSQL "variables" are really macros used in text expansion, not true values. I'm sure that comes in handy, but it's tricky at first.
关于 PSQL 变量的最后一句话:
如果您在 SQL 语句中将它们用单引号引起来,它们就不会扩展。
因此这不起作用:
要在 SQL 语句中扩展为字符串文字,您必须在变量集中包含引号。 但是,变量值已经必须用引号引起来,这意味着您需要第二组引号,并且内部组必须被转义。 因此你需要:
编辑:从 PostgreSQL 9.1 开始,您可以改为编写:
One final word on PSQL variables:
They don't expand if you enclose them in single quotes in the SQL statement.
Thus this doesn't work:
To expand to a string literal in a SQL statement, you have to include the quotes in the variable set. However, the variable value already has to be enclosed in quotes, which means that you need a second set of quotes, and the inner set has to be escaped. Thus you need:
EDIT: starting with PostgreSQL 9.1, you may write instead:
您可以尝试使用 WITH 子句。
You can try to use a WITH clause.
Postgres 变量是通过 \set 命令创建的,例如 ...
... 然后可以被替换,例如 ...
... 或 ...
编辑:从 psql 9.1 开始,变量可以在引号中展开,如下所示:
在旧版本的 psql 客户端中:
... 如果您想使用变量作为条件字符串查询中的值,例如 ...
...那么您需要在变量本身中包含引号,因为上面的方法不起作用。 相反,这样定义您的变量...
但是,如果像我一样,您遇到了想要从现有变量创建字符串的情况,我发现技巧就是这样...
现在您都有一个带引号的和同一字符串的不带引号的变量! 你可以做这样的事情......
Postgres variables are created through the \set command, for example ...
... and can then be substituted, for example, as ...
... or ...
edit: As of psql 9.1, variables can be expanded in quotes as in:
In older versions of the psql client:
... If you want to use the variable as the value in a conditional string query, such as ...
... then you need to include the quotes in the variable itself as the above will not work. Instead define your variable as such ...
However, if, like me, you ran into a situation in which you wanted to make a string from an existing variable, I found the trick to be this ...
Now you have both a quoted and unquoted variable of the same string! And you can do something like this ....
特别是对于
psql
,您也可以从命令行传递psql
变量; 您可以使用-v
传递它们。 这是一个用法示例:请注意,冒号不带引号,然后变量名称本身被引号引起来。 我知道语法很奇怪。 这仅适用于 psql,但不适用于
-c
/--command
; 您必须通过 stdin 或通过-f
发送命令。 它在(例如)PgAdmin-III 中也不起作用。这种替换发生在 psql 的输入处理过程中,因此您不能(比如说)定义使用
:'filepath'
的函数并期望:'filepath'
的值从一个会话到另一个会话的更改。 当函数被定义时,它将被替换一次,然后将是一个常量。 它对于脚本编写很有用,但对于运行时使用却没有用。Specifically for
psql
, you can passpsql
variables from the command line too; you can pass them with-v
. Here's a usage example:Note that the colon is unquoted, then the variable name its self is quoted. Odd syntax, I know. This only works in psql but doesn't work with
-c
/--command
; you have to send the command via stdin or via-f
. It won't work in (say) PgAdmin-III too.This substitution happens during input processing in psql, so you can't (say) define a function that uses
:'filepath'
and expect the value of:'filepath'
to change from session to session. It'll be substituted once, when the function is defined, and then will be a constant after that. It's useful for scripting but not runtime use.