PostgreSQL 语法检查,无需运行查询

PostgreSQL syntax check without running the query

提问人:Rob Audenaerde 提问时间:11/26/2011 最后编辑:Rob Audenaerde 更新时间:11/17/2023 访问量:78912

问:

我想先验证包含 sql 查询的文件的语法,然后才能在我的 CVS 项目中提交它们。

为了做到这一点,我有一个commitinfo脚本,但我很难确定sql命令是否有效。 似乎没有试运行模式,从语法(即源代码中)构建我自己的 postgresql-dialact 测试器似乎是一个很长的过程。psql

脚本可能包含多个查询,因此不能围绕它们进行包装。EXPLAIN

有什么提示吗?

SQL 解析 PostgreSQL 语法 CVS

评论

0赞 triclosan 11/26/2011
我在 postgresql 块上有 SP 的相关问题,直到未调用才进行验证
7赞 Erwin Brandstetter 11/26/2011
@triclosan:您可能对 PLPGSQL lint 感兴趣,它恰好解决了这个缺点。Pavel Stěhule 是主要开发者。请参阅此博客文章
1赞 Ben Sutton 9/9/2016
我对postgres不是很有经验,所以这可能是一个糟糕的解决方法,不值得真正的答案,但我只是在脚本末尾添加了一个垃圾行,我知道这会导致错误。如果它遇到的第一个错误是垃圾行,我可以合理地确信脚本的其余部分是正常的。与事务不同,它保留序列值,对于简单的脚本,它比下载另一个实用程序更快、更容易。

答:

15赞 Erwin Brandstetter 11/26/2011 #1

一种方法是将其放入最后回滚的事务中:

BEGIN;
<query>;
<query>;
<query>;
ROLLBACK;

请注意,有些效果是无法回滚的,例如 dblink 调用、写入文件系统的任何内容或递增的序列。

我建议克隆您的数据库以进行测试。

评论

0赞 Rob Audenaerde 11/26/2011
这只能通过活动连接来完成。我宁愿进行静态检查。如果我的 sql 中有 BEGIN 语句,这不会中断吗?
0赞 Erwin Brandstetter 11/26/2011
@RobAu:其他将被忽略。将发布 A。BEGIN;WARNING
1赞 wildplasser 11/26/2011
@RobAu:静态检查不适用于动态查询。嗯:并非总是如此。你唯一能做的就是沙盒和祈祷。
1赞 Sonic Soul 6/20/2019
这是一个非常糟糕的主意。有大量有效的 SQL 语句会根据数据库的状态抛出错误。事务也适用于 CRUD,但不适用于架构更改,这也是 SQL
7赞 aleroot 11/26/2011 #2

我通常使用 Mimer 在线 SQL 验证器,唯一的问题是它检查标准 SQL 的 SQL 语法:

  • SQL-92的
  • SQL-99型
  • SQL-03型

并且不特定于 PostgreSQL ...但是,如果您按照标准编写代码,则可以使用它并且运行良好......

评论

0赞 corsiKa 12/19/2015
这样做的好处是可以更轻松地切换数据库。我喜欢postgres,近年来它变得更好了,但很长一段时间以来,它的基本理念似乎是“标准?我们要去哪里,我们不需要标准。
0赞 OzzyTheGiant 7/23/2020
缺点是,如果您的表名或列名包含大写字母等,则这些标识符需要用引号书写,我认为这不是其他数据库中的约定。
61赞 Mark Drago 11/3/2012 #3

我最近写了一个实用程序来静态检查 PostgreSQL 的 SQL 语法。它利用 postgres 的嵌入式 SQL C preproccessor ecpg 来检查 SQL 语法,因此它使用与 Postgres 本身内置的完全相同的解析器。

您可以在 github 上查看:http://github.com/markdrago/pgsanity。您可以浏览 README,以更好地了解它的工作原理并获取有关如何安装它的说明。下面是一个如何使用 pgsanity 的简短示例:

$ pgsanity good1.sql good2.sql bad.sql
bad.sql: line 1: ERROR: syntax error at or near "bogus_token"

$ find -name '*.sql' | xargs pgsanity
./sql/bad1.sql: line 59: ERROR: syntax error at or near ";"
./sql/bad2.sql: line 41: ERROR: syntax error at or near "insert"
./sql/bad3.sql: line 57: ERROR: syntax error at or near "update"

评论

0赞 Rob Audenaerde 11/3/2012
这看起来很有帮助。我很快就会检查一下
5赞 while 5/21/2013
谢谢你的pgsanity!这真的很方便。有没有办法在 systastic 中使用 pgsanity (github.com/scrooloose/syntastic)?在 vim 中保存文件时自动运行检查真是太棒了。
0赞 Mark Drago 7/5/2013
@while我敢打赌,将它添加到合成中并不难。我从未使用过 syntastic,也没有 vim foo 自己添加它。但是,由于 pgsanity 在成功时返回 0 或在失败时返回非零,我敢打赌添加它会相对容易。
1赞 nelsonic 3/31/2019
很棒的工具@MarkDrago经过数小时的调试后救了我。:-)
0赞 LondonRob 3/25/2021
看起来这不再被开发了。是吗?
1赞 Jeff Wu 10/17/2015 #4

你可以把它包起来SELECT 1 ( <your query> ) AS a WHERE 1 = 0;

它会在验证时失败,但实际上不会执行。下面是一个示例查询计划:

Result  (cost=0.00..0.01 rows=1 width=0)
  One-Time Filter: false

评论

0赞 Rob Audenaerde 10/18/2015
如何将多个sql语句包装在一次选择中?
0赞 Jeff Wu 10/23/2015
你能只运行多个 select 语句吗?或者你可以在开始时使用 WITH 块。
6赞 Anshul Tiwari 5/4/2016 #5

验证 SQL 语法的绝妙实用程序:SQL Fiddle

支持 MySQL、Oracle、PostgreSQL、SQLite、MS SQL。

11赞 karlgold 5/31/2016 #6

EXPLAIN(不带 ANALYZE)将解析查询并准备执行计划,而不实际执行它。

https://www.postgresql.org/docs/current/static/sql-explain.html

评论

0赞 Rob Audenaerde 5/31/2016
感谢您抽出宝贵时间写答案,但正如我在问题中已经解释的那样,我不能使用 EXPLAIN。
1赞 shcherbak 3/10/2017 #7

您可以在 postgresql 函数之外运行查询,并在最后引发异常。所有更改都将回滚。例如:

CREATE OR REPLACE FUNCTION run_test(_sp character varying)
  RETURNS character varying AS
$BODY$
BEGIN
  EXECUTE 'SELECT ' || _sp;
  RAISE EXCEPTION '#OK';
EXCEPTION
  WHEN others THEN
    RETURN SQLERRM;
END;
$BODY$
  LANGUAGE plpgsql VOLATILE
  COST 100;

另一个解决方案 - 扩展(在 github 上),pgpsql_lint 的下一个化身plpgsql_check

评论

0赞 shcherbak 3/10/2017
您可以编写一个返回 void 的包装器,并将所有 DML 包含在设置环境中,运行特定函数和查询,然后以“RAISE EXCEPTION”退出。尝试在 Google 上寻找一些 Pgunit。他们使用这样的技术
47赞 Rinat 3/4/2020 #8

使用此技巧验证 PostgreSQL 代码语法:

DO $SYNTAX_CHECK$ BEGIN RETURN;
    -- insert your SQL code here
END; $SYNTAX_CHECK$;

函数 is_sql(sql text)(链接到我的 GitHub)

评论

0赞 samvel1024 12/24/2021
如果查询包含,它会没有副作用吗?commit;
0赞 Steven Kalt 1/2/2022
@samvel1024是的,不会运行。您可以通过以下实验进行验证:。即使您将交易移出区块,交易仍然不会被提交。commitCREATE TABLE foo(id int); DO $$ BEGIN RETURN; BEGIN; INSERT INTO foo VALUES (1); COMMIT; END; $$; SELECT * FROM foo;BEGINDO
0赞 Steven Kalt 1/2/2022
看起来这个技巧接受 plpgsql 语法,这不是有效的 SQL。例如,works while 在 plpgsql 之外无效。DO $$ BEGIN RETURN; IF true THEN select 1; END IF; END; $$;IF ... THEN ... END IF
1赞 Reddspark 4/13/2022
给菜鸟的提示。如果得到,那么你可能在SQL语句的末尾缺少一个分号ERROR: syntax error at or near "END"
0赞 Rinat 4/21/2022
当您的代码进入 时,您将收到一个错误。但是有一个解决方法SAVEPOINT my_savepoint; ...; ROLLBACK TO SAVEPOINT my_savepoint;DO