Liquibase:MySQL 存储过程中的 SQL 语法错误

Posted

技术标签:

【中文标题】Liquibase:MySQL 存储过程中的 SQL 语法错误【英文标题】:Liquibase: SQL syntax error in a MySQL stored procedure 【发布时间】:2018-02-16 10:36:01 【问题描述】:

我尝试通过 Liquibase 运行 mysql 存储过程 SQL 脚本,但没有成功。

db.storedprocedure.xml的内容

<changeSet author="zzz" id="1" runOnChange="true" runInTransaction="true">
    <sqlFile path="changelogs/change_03.sql"
         relativeToChangelogFile="true"
         endDelimiter="$$"
         stripComments="false"
         splitStatements="false"/>
</changeSet>

我的SQL文件change_03.sql的内容:

$$

CREATE PROCEDURE `liqui01`.`User_Search`(
    INOUT id INT,
    OUT name VARCHAR(50)
)
BEGIN

    SET @sql = CONCAT("SELECT id, name FROM user WHERE da.MarketId = ", id );

    PREPARE stmt from @sql;
    EXECUTE stmt;

END$$

它显示如下错误:

运行 Liquibase 时出现意外错误:您的 SQL 中有错误 句法;检查与您的 MySQL 服务器版本相对应的手册 在 '$$ ...

附近使用正确的语法

我试过把“$$”改成其他的分隔符,或者把SQL放到XML文件的&lt;sql&gt;标签里面,都不行。

任何建议将不胜感激!

更新 1

@Shadow 给出了正确答案(很遗憾我无法将其标记为答案,因为它在 cmets 中),从 sql 脚本中删除分隔线将使其工作,谢谢他!

现在的问题是:如何使用“endDelimiter”参数?

【问题讨论】:

为什么在存储过程的开头有一个 $$?这不是必需的。另请注意,此查询不需要准备好的语句(这与您收到的错误消息无关) @Shadow 嗨,伙计,你节省了我的时间!仍然想知道为什么“endDelimiter”不起作用,以及为什么他们提供这样的参数......我从其他存储过程中复制了脚本,并删除了一些其他部分,只是为了测试 liquibase,但忘记删除“prepare stmt”部分: ) 请参考完整程序-> ***.com/questions/1267172/mysql-delimiter-error/… 【参考方案1】:

我在互联网上搜索了解决方案。看来 Liquibase 将在 update 命令上很好地创建存储过程。但是在 updateSQL 命令上崩溃了,因为它输出了无效的 SQL。

我的解决方案是将 cmets 添加到 changesets sql 标签。目的是使用正则表达式来清理输出 sql。

我正在使用的.sql 文件有一些 liquibase 不喜欢的关键字,例如DELIMITER,所以我使用 &lt;modifysql&gt;&lt;regExpReplace&gt;.sql 文件进行 lint / sanitize。 这样,.sql 文件就可以被 liquibase 使用,并且可以在update 上成功运行而不会出现错误。

但是,我们仍然会在 updateSQL 上输出无效的 SQL。为了解决这个问题,我在无效的输出.sql 文件上使用另一个正则表达式搜索/替换来查找 cmets; -- DELIMITER $$

例子:

<changeSet id="Test1" author="author_name" context="master" runOnChange="true">
    <validCheckSum>any</validCheckSum>
    <sql><![CDATA[
        DROP PROCEDURE IF EXISTS `sp_myProcedure`;
        -- DELIMITER $$
    ]]></sql>
    <createProcedure path="yourpath/procs/sp_myProcedure.sql" relativeToChangelogFile="true" />
    <sql><![CDATA[
        -- $$ DELIMITER;
    ]]></sql>
    <modifySql>
        <regExpReplace replace="[^]+CREATE PROCEDURE" with="CREATE PROCEDURE"/>
    </modifySql>
    <modifySql>
        <regExpReplace replace="END\s*\$\$[^]*" with="END"/>
    </modifySql>
</changeSet>  

【讨论】:

【参考方案2】:

liquibase 内部将delimiter 命令添加到命令开头,您必须删除或用$$ 注释第一行:

-- $$

CREATE PROCEDURE `liqui01`.`User_Search`(

...

END$$

【讨论】:

感谢您的建议,但不幸的是它不起作用,错误消息有点不同:... use near '' at line 12 ... (not "near '$$' ...") 删除CREATE PROCEDURE之前的所有字符并运行liquibase。 谢谢伊万,但这不起作用,它显示的错误与我之前的评论相同。

以上是关于Liquibase:MySQL 存储过程中的 SQL 语法错误的主要内容,如果未能解决你的问题,请参考以下文章

使用 Liquibase 创建雪花存储过程

Learning-MySQL:视图触发器存储过程函数流程控制

如何使 liquibase 的 LoadData 标签不区分大小写?

液化石油气。如何跟踪存储过程更改

从 MySQL 中的现有表生成更改日志时,liquibase 如何处理自动递增的 PK?

使用 liquibase 插入空值