【问题标题】:How to get more than 1000 items in HSQLDB in CASE WHEN statement?如何在 CASE WHEN 语句中获取 HSQLDB 中超过 1000 个项目?
【发布时间】:2009-01-12 22:11:14
【问题描述】:

我正在 Hypersonic DB (HSQLDB) 中运行以下查询:

SELECT (CASE foo WHEN 'a' THEN 'bar' WHEN 'b' THEN 'biz' ....
        ELSE 'fin' END ) FROM MyTable LIMIT 1

当“WHEN”子句的数量超过大约 1000 个时,我在 org.hsqldb.jdbc.Util.sqlException() 中得到一个由 JDBC 驱动程序抛出的 Java StackOverflowError

这是真正奇怪的部分:我尝试将我的 CASE 声明分解为例如100 个 WHEN 子句后跟 ELSE ( CASE foo WHEN ... ) END。但即使进行了这种重写,我也得到了完全相同的行为!

我在 HSQLDB 手册中没有看到任何对 1000 或其他限制的引用。救命!

【问题讨论】:

    标签: sql hsqldb stack-overflow


    【解决方案1】:

    CASE 语句中,您永远不应该接近 1000 个术语。在此之前,您应该将其他值放入单独的表中并通过连接来选择它们。

    INSERT INTO MappingTable (foo, string) VALUES
      ('a', 'bar'), ('b', 'biz'), ...
    
    SELECT COALESCE(m.string, 'fin')
    FROM MyTable t LEFT OUTER JOIN MappingTable m USING (foo)
    LIMIT 1;
    

    Java API 说 StackOverflowError:

    由于应用程序递归太深而发生堆栈溢出时引发。

    所以我猜想,当 HSQLDB 解析 CASE 表达式时,每个 WHEN 术语都会向运行时堆栈添加另一层(实际上每个 WHEN 可能有几层)。

    如果您有一个包含 1,000 级嵌套括号的算术表达式,您可能会收到类似的 StackOverflowError。

    1,000 的限制可能是可变的,具体取决于 Java VM 的实现、Java 的版本、您运行的平台、可用内存量等。他们可能不会在 HSQLDB 文档中记录它因为它是特定于平台的限制,而不是 HSQLDB 内置的限制。

    【讨论】:

    • 是的,我知道这是一个糟糕的设计。但是,我仍然希望得到原始问题的答案。
    • 是的,我做到了。问题是如何在 CASE 语句中获取 1000 多个项目。我同意你关于为什么会发生这种情况的评估......也许这意味着这是不可能的!
    • 他们在那个级别使用递归也很可悲和令人惊讶,但这是最可能的原因。我希望有人以前会遇到过这种情况并且可能有一个技巧 - 例如使用不同的语句? -- 解决这个问题。
    • 如果不是,我当然会将您的答案标记为“正确”——这是不可能的,因为他们的设计和您给出的更正似乎是最合乎逻辑的(除了 INNER 不像其他地方描述的那样工作) -- 你可能也想解决这个问题。
    • LEFT JOIN 是外连接。 OUTER 关键字是可选的。
    【解决方案2】:

    完全消除 CASE 语句。

    使用这 1000 个值创建一个表,然后对该表进行内部连接。

    【讨论】:

    • 他无法使用内部连接获得 ELSE 值。
    • 是的。我可以将 OUTER 和 ifnull() 用于 ELSE 值。这确实有效,但我想要原始问题的答案而不是架构更改。是的,我知道架构更改更智能。
    【解决方案3】:

    正如比尔所说,鉴于明显的 HSQL 解析器设计,不可能移除限制。

    在减轻限制方面(即让自己通过将限制推到...超过 1000 个开关来达到 1000 个开关),您有两种选择。

    1. 在运行应用程序时增加 VM 中的堆栈大小。如果您使用的是 Sun 的 Hotspot VM,您应该能够通过例如-XX:ThreadStackSize=1024 每个线程使用 1MB 堆栈,而不是默认的 512K。这可能会让您获得更大的递归深度。
    2. 您可以在由构造函数 Thread(ThreadGroup, Runnable, String, long) 创建的线程中运行您的工作,其中最后一个参数是请求的堆栈大小。这可能有效,也可能无效;如果您阅读 Javadoc,这是一个建议——非常欢迎 VM 忽略此请求。不确定 Hotspot 的具体用途,但它可能会有所帮助。

    【讨论】:

      猜你喜欢
      • 2014-10-30
      • 2013-01-07
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2013-04-23
      • 1970-01-01
      • 2019-01-10
      相关资源
      最近更新 更多