如何在 Postgres 查询窗口中使用参数测试我的 ad-hoc SQL

Posted

技术标签:

【中文标题】如何在 Postgres 查询窗口中使用参数测试我的 ad-hoc SQL【英文标题】:How to test my ad-hoc SQL with parameters in Postgres query window 【发布时间】:2015-07-22 15:39:17 【问题描述】:

在 Microsoft SQL Server 中,在查询窗口中测试类似这样的内容:

select * from Users where LastName = @lastname

我可以在命令前加上这个:

declare @lastname varchar(16)
set @lastname = 'Troy'

但在 PostgreSQL 中,我找不到类似的方法。看来我唯一能做的就是直接用它的值替换参数名称。当临时查询变得复杂并且多次使用相同的参数时,这会变得很困难。有什么办法吗?

【问题讨论】:

顺便说一句:“Postgres 查询窗口”?你的意思是 pgAdmin 查询窗口? 我也习惯了 MSSQL 的工作流程,将参数化查询复制到查询运行器中,在其上方设置声明,然后点击运行。这样我就不会在修改它以进行测试的过程中错误地更改查询语义。令人失望的是,在 postgres 中没有办法做到这一点。必须始终更改参数化查询(至少,变量名称或插入转换)来测试它并冒着测试结果无效的风险。 工作流也存在于 mysql 中,使用 SET @var = 123。 ***.com/questions/11754781/…。我知道我在 MSSQL 之前使用过它。 【参考方案1】:

多种选择。

在CTE 中提供参数以在纯SQL中拥有“变量”:

WITH var(lastname) AS (SELECT 'Troy'::varchar(16))
SELECT *
FROM   users, var v
WHERE  lastname = v.lastname;

这适用于任何查询。 由于 CTE var 包含 单行,因此在 FROM 子句末尾附加 CROSS JOIN 是安全的 - 实际上是附加它的简短形式在逗号之后可能是最好的,因为显式连接语法在逗号之前绑定。额外的表别名v 是可选的以进一步缩短语法。

不带 CTE 更便宜。顺便说一句,为什么varchar(16)?只需使用text

SELECT *
FROM   users
JOIN  (SELECT 'Troy'::text) var(lastname) USING (lastname)
WHERE  lastname = var.lastname;

使用临时表为同一会话中的所有查询发挥类似的作用。临时表在会话结束时终止。

CREATE TEMP TABLE var AS
SELECT text 'Troy' AS lastname;

ANALYZE var;  -- temp tables are not covered by autovacuum

SELECT * FROM users JOIN var USING (lastname);
About temporary tables and autovacuum

或者您可以使用 DO 语句,如 @Houari 提供的或此处演示的:

PostgreSQL loops outside functions. Is that possible?

请注意,您不能从 DO 语句返回值。 (不过,您可以使用RAISE ...。)并且您不能在 plpgsql 中使用没有目标的SELECT - DO 语句中的默认过程语言。将 SELECT 替换为 PERFORM 以丢弃结果。

或者您可以使用customized options,您可以在postgresql.conf 中将其设置为全局可见

在您的会话中设置为在会话期间可见并且仅在同一会话中

SET my.lastname = 'Troy';

变量名必须包含一个点。这种方式仅限于 text 作为数据类型,但任何数据类型都可以表示为 text ...

您可以使用current_setting('my.lastname') 作为值表达式。如果需要,请投射。例如:current_setting('my.json_var')::json ...

使用SET LOCAL 使效果仅持续当前事务。见:

Passing user id to PostgreSQL triggers

或者您可以使用微小的IMMUTABLE函数作为只有特权用户才能操作的全局持久变量。见:

Is there a way to define a named constant in a PostgreSQL query?

当使用psql 作为客户端时,使用\set\gset 元命令和variable substitution。

【讨论】:

临时表选项给我带来了很多麻烦。这是一个隐式连接,需要在更新子句中使用 FROM,这使得它需要几分钟才能运行。 @Noumenon:注意添加的关于临时表和自动清理的位。【参考方案2】:

也许使用DO 指令来模拟一个函数。通过这种方式,您可以声明变量并使用它们来执行您的查询!

http://www.postgresql.org/docs/9.4/static/sql-do.html

【讨论】:

我试过了,但是它总是得到一个 sql 错误:错误:查询没有结果数据的目的地 SQL 状态:42601 提示:如果你想丢弃 SELECT 的结果,请改用 PERFORM。上下文:SQL 语句中的 PL/pgSQL 函数 inline_code_block 第 5 行 DO $$ DECLARE startDate Timestamp; BEGIN startDate := '2014-4-1';从 grouping_horizo​​ntal 中选择 pid,其中 dt = startDate;结束 $$; @Carol:提示说明了一切:使用关键字PERFORM 而不是SELECT。您不能在 DO 语句中没有目标的 SELECT 并且不能返回行...【参考方案3】:

我将postgres配置为记录所有命令,并从日志文件中复制命令,因此所有参数都已替换为值,并在查询窗口中测试命令。

可能不是最好的方法,但它很容易并且对我有用

【讨论】:

以上是关于如何在 Postgres 查询窗口中使用参数测试我的 ad-hoc SQL的主要内容,如果未能解决你的问题,请参考以下文章

使用窗口函数在 Postgres 上使用 SqlAlchemy 限制查询

在子查询的FROM中使用Postgres窗口语句

如何使用 TypeORM 为 postgres 数据库和 nodejs 使用参数化查询作为应用程序的后端服务器

postgres:从带有参数的查询中获取可执行查询

Postgres:计算子查询中的唯一数组条目

使用count distinct在postgres中进行慢速查询