【问题标题】:CTE based sequence generation with HSQLDB使用 HSQLDB 生成基于 CTE 的序列
【发布时间】:2017-11-12 07:50:36
【问题描述】:

我正在使用递归公用表表达式来获取一批序列号。以下查询适用于 Postgres、SQL Server 和 H2(减去 VALUES 部分)。

WITH RECURSIVE t(n, level_num) AS (
    SELECT next value for seq_parent_id as n,
           1 as level_num
      FROM (VALUES(0))

    UNION ALL

    SELECT next value for seq_parent_id as n,
           level_num + 1 as level_num
      FROM t
     WHERE level_num < ?)
SELECT n FROM t

但是使用 HSQLDB 2.4.0 我得到以下异常

java.sql.SQLSyntaxErrorException: user lacks privilege or object not found: T
    at org.hsqldb.jdbc.JDBCUtil.sqlException(Unknown Source)
    at org.hsqldb.jdbc.JDBCUtil.sqlException(Unknown Source)
    at org.hsqldb.jdbc.JDBCStatement.fetchResult(Unknown Source)
    at org.hsqldb.jdbc.JDBCStatement.executeQuery(Unknown Source)
    ... 
Caused by: org.hsqldb.HsqlException: user lacks privilege or object not found: T
    at org.hsqldb.error.Error.error(Unknown Source)
    at org.hsqldb.error.Error.error(Unknown Source)
    at org.hsqldb.ParserDQL.readTableName(Unknown Source)
    at org.hsqldb.ParserDQL.readTableOrSubquery(Unknown Source)
    at org.hsqldb.ParserDQL.XreadTableReference(Unknown Source)
    at org.hsqldb.ParserDQL.XreadFromClause(Unknown Source)
    at org.hsqldb.ParserDQL.XreadTableExpression(Unknown Source)
    at org.hsqldb.ParserDQL.XreadQuerySpecification(Unknown Source)
    at org.hsqldb.ParserDQL.XreadSimpleTable(Unknown Source)
    at org.hsqldb.ParserDQL.XreadQueryPrimary(Unknown Source)
    at org.hsqldb.ParserDQL.XreadQueryTerm(Unknown Source)
    at org.hsqldb.ParserDQL.XreadSetOperation(Unknown Source)
    at org.hsqldb.ParserDQL.XreadQueryExpressionBody(Unknown Source)
    at org.hsqldb.ParserDQL.XreadQueryExpression(Unknown Source)
    at org.hsqldb.ParserDQL.XreadSubqueryTableBody(Unknown Source)
    at org.hsqldb.ParserDQL.XreadTableNamedSubqueryBody(Unknown Source)
    at org.hsqldb.ParserDQL.XreadQueryExpression(Unknown Source)
    at org.hsqldb.ParserDQL.compileCursorSpecification(Unknown Source)
    at org.hsqldb.ParserCommand.compilePart(Unknown Source)
    at org.hsqldb.ParserCommand.compileStatements(Unknown Source)
    at org.hsqldb.Session.executeDirectStatement(Unknown Source)
    at org.hsqldb.Session.execute(Unknown Source)
    ... 37 more

这个特定的用例也可以通过 UNNESTSEQUENCE_ARRAY 的组合来解决,但我想避免引入 HSQLDB 特定的代码路径。

【问题讨论】:

    标签: sql sequence hsqldb common-table-expression


    【解决方案1】:

    我将从不使用序列和硬编码限制的最简单形式的递归查询开始,然后逐渐向其中添加额外的位。

    根据文档With Clause and Recursive Queries 中的示例,语法应如下所示:

    WITH RECURSIVE
    t(level_num)
    AS
    (
        VALUES(1)
    
        UNION ALL
    
        SELECT
            level_num + 1
        FROM t
        WHERE level_num < 10
    )
    SELECT level_num 
    FROM t
    ;
    

    顺便说一句,文档说:

    HyperSQL 将递归限制为 265 轮。如果超过此值,则会出现错误 被提升了。

    我会尝试最简单的查询,例如上面的查询,确保它有效,然后尝试使用 1000 而不是 10 并查看它返回什么错误。如果和你原来的错误一样,那么你找到了原因。


    附注:对于此类任务,我会使用永久的数字表,而不是动态地递归生成它们。我们的系统中有一个包含 100K 数字的表格。它很简单,适用于任何 DBMS。填充一次并根据需要使用。我知道在 SQL Server 递归查询中(在这种任务中)要慢得多,但我不知道 HyperSQL。此外,递归深度限制为 265 是相当苛刻的。很可能,由于递归深度的限制如此之低,因此不可能检测到性能上的任何差异。但是,再一次,265 个数字是否足以满足您的目的?

    【讨论】:

    • 如果我执行你的代码,查询永远不会返回,但会消耗大量 CPU。查询是否为您运行?我对 265 轮的递归限制很好,我不希望用户使用超过 100 轮(他们,我知道)。这是“框架”代码,所以我不想将数字表强加给用户。
    • 抱歉,我手头没有 HSQLDB 可以尝试。我写它只看文档。主要观点仍然成立。我会尝试做最简单的递归查询,然后一一添加额外的位。比如,增加迭代次数,然后增加序列的使用。
    • 我同意,我尝试了您的代码,但我不知道如何进一步简化它,并且它在没有错误消息的情况下失败(只是烧毁 CPU)。所以我在这里有点不知所措。
    【解决方案2】:

    HSQLDB 的“UNION ALL”有问题。在上面提到的示例“使用子句和递归查询”中,没有“UNION ALL”,而只有“UNION”(请注意,文档可能会更改)。 在this thread 中有一些关于它的讨论。但目前我无法在使用 UNION ALL 的 HSQLDB 中获得有效的递归语句。

    所以在 HSQLDB v 2.3.2+ 中使用 UNION

    【讨论】:

      猜你喜欢
      • 2021-10-18
      • 2012-05-13
      • 2011-06-10
      • 2011-04-10
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多