如何声明要在PostgreSQL 8.3查询中使用的变量?
在MS SQL Server中,我可以这样做:
DECLARE @myvar INT
SET @myvar = 5
SELECT *
FROM somewhere
WHERE something = @myvar
我如何在PostgreSQL中做同样的事情?根据文档,变量被简单地声明为“名称类型;”,但这给了我一个语法错误:
myvar INTEGER;
有人可以给我一个正确语法的例子吗?
如何声明要在PostgreSQL 8.3查询中使用的变量?
在MS SQL Server中,我可以这样做:
DECLARE @myvar INT
SET @myvar = 5
SELECT *
FROM somewhere
WHERE something = @myvar
我如何在PostgreSQL中做同样的事情?根据文档,变量被简单地声明为“名称类型;”,但这给了我一个语法错误:
myvar INTEGER;
有人可以给我一个正确语法的例子吗?
Answers:
PostgreSQL中没有这样的功能。您只能在pl / PgSQL(或其他pl / *)中执行此操作,而不能在普通SQL中执行。
WITH ()
可以用作变量甚至tuple
是变量的查询是一个例外。它允许您返回一个临时值表。
WITH master_user AS (
SELECT
login,
registration_date
FROM users
WHERE ...
)
SELECT *
FROM users
WHERE master_login = (SELECT login
FROM master_user)
AND (SELECT registration_date
FROM master_user) > ...;
我通过使用WITH
子句实现了相同的目标,虽然它虽然不那么优雅,但可以做同样的事情。尽管对于这个例子来说,这确实太过分了。我也不特别推荐这样做。
WITH myconstants (var1, var2) as (
values (5, 'foo')
)
SELECT *
FROM somewhere, myconstants
WHERE something = var1
OR something_else = var2;
\set
按照Shahriar Aghajani的答案中的建议使用。
JOIN myconstants ON true
然后就不需要进行子选择了。
WITH
在事务中的所有查询之间共享CTE。
WITH constants AS (SELECT 5 AS var) SELECT * FROM somewhere CROSS JOIN constants WHERE someting=var;
。带有单行表表达式的CROSS JOIN实际上复制了真实表中所有行的数据,并简化了表达式。
您也可以在PLPGSQL中尝试此操作:
DO $$
DECLARE myvar integer;
BEGIN
SELECT 5 INTO myvar;
DROP TABLE IF EXISTS tmp_table;
CREATE TABLE tmp_table AS
SELECT * FROM yourtable WHERE id = myvar;
END $$;
SELECT * FROM tmp_table;
以上要求Postgres 9.0或更高版本。
您可以为此“滥用”动态配置设置:
-- choose some prefix that is unlikely to be used by postgres
set session my.vars.id = '1';
select *
from person
where id = current_setting('my.vars.id')::int;
配置设置始终是varchar值,因此在使用它们时需要将其转换为正确的数据类型。这适用于任何SQL客户端,而\set
仅适用于psql
以上要求Postgres 9.2或更高版本。
对于以前的版本,必须在以下位置声明变量 postgresql.conf
之前,因此它在某种程度上限制了其可用性。实际上不是完全变量,而是配置“类”,它实际上是前缀。但是,一旦定义了前缀,就可以使用任何变量而无需更改postgresql.conf
set session my.vars.id = '1';
为set session my.user.id = '1';
将产生ERROR: syntax error at or near "user"
SET LOCAL ...
。该session
变量将在您连接时一直有效。该local
属性的范围交易。
set session "my.user.id" = '1';
该current_setting('my.user.id')
呼叫按预期运行。
这取决于您的客户。
但是,如果使用的是psql客户端,则可以使用以下命令:
my_db=> \set myvar 5
my_db=> SELECT :myvar + 1 AS my_var_plus_1;
my_var_plus_1
---------------
6
如果使用文本变量,则需要引用。
\set myvar 'sometextvalue'
select * from sometable where name = :'myvar';
\set
必须为小写字母
db=> \set someid 8292 db=> SELECT * FROM sometable WHERE id = :someid;
我想对@DarioBarrionuevo的答案提出一个改进,以使其更容易利用临时表。
DO $$
DECLARE myvar integer = 5;
BEGIN
CREATE TEMP TABLE tmp_table ON COMMIT DROP AS
-- put here your query with variables:
SELECT *
FROM yourtable
WHERE id = myvar;
END $$;
SELECT * FROM tmp_table;
1
(大概是行数)而不是的内容tmp_table
。
此解决方案基于fei0x提出的解决方案,但它的优点是无需在查询中加入常量的值列表,并且可以在查询开始时轻松列出常量。它也适用于递归查询。
基本上,每个常量都是在WITH子句中声明的单值表,然后可以在查询其余部分的任何位置调用它。
WITH
constant_1_str AS (VALUES ('Hello World')),
constant_2_int AS (VALUES (100))
SELECT *
FROM some_table
WHERE table_column = (table constant_1_str)
LIMIT (table constant_2_int)
或者,您可以使用SELECT * FROM constant_name
代替TABLE constant_name
对其他不同于postgresql的查询语言无效的语言。
这是一个使用PREPARE语句的示例。您仍然不能使用?
,但是可以使用$n
符号:
PREPARE foo(integer) AS
SELECT *
FROM somewhere
WHERE something = $1;
EXECUTE foo(5);
DEALLOCATE foo;