如何在 CASE WHEN 语句中获取 HSQLDB 中超过 1000 个项目?
Posted
技术标签:
【中文标题】如何在 CASE WHEN 语句中获取 HSQLDB 中超过 1000 个项目?【英文标题】:How to get more than 1000 items in HSQLDB in CASE WHEN statement? 【发布时间】: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 ***Error
。
这是真正奇怪的部分:我尝试将我的 CASE
声明分解为例如100 个 WHEN 子句后跟 ELSE ( CASE foo WHEN ... ) END
。但即使进行了这种重写,我也得到了完全相同的行为!
我在 HSQLDB 手册中没有看到任何对 1000 或其他限制的引用。救命!
【问题讨论】:
【参考方案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 说 ***Error:
由于应用程序递归太深而发生堆栈溢出时引发。
所以我猜想,当 HSQLDB 解析 CASE
表达式时,每个 WHEN
术语都会向运行时堆栈添加另一层(实际上每个 WHEN
可能有几层)。
如果您有一个包含 1,000 级嵌套括号的算术表达式,您可能会收到类似的 ***Error。
1,000 的限制可能是可变的,具体取决于 Java VM 的实现、Java 的版本、您运行的平台、可用内存量等。他们可能不会在 HSQLDB 文档中记录它因为它是特定于平台的限制,而不是 HSQLDB 内置的限制。
【讨论】:
是的,我知道这是一个糟糕的设计。但是,我仍然希望得到原始问题的答案。 是的,我做到了。问题是如何在 CASE 语句中获取 1000 多个项目。我同意你关于为什么会发生这种情况的评估......也许这意味着这是不可能的! 他们在那个级别使用递归也很可悲和令人惊讶,但这是最可能的原因。我希望有人以前会遇到过这种情况并且可能有一个技巧 - 例如使用不同的语句? -- 解决这个问题。 如果不是,我当然会将您的答案标记为“正确”——这是不可能的,因为他们的设计和您给出的更正似乎是最合乎逻辑的(除了 INNER 不像其他地方描述的那样工作) -- 你可能也想解决这个问题。 LEFT JOIN 是外连接。 OUTER 关键字是可选的。【参考方案2】:完全消除 CASE 语句。
使用这 1000 个值创建一个表,然后对该表进行内部连接。
【讨论】:
他无法使用内部连接获得 ELSE 值。 是的。我可以将 OUTER 和 ifnull() 用于 ELSE 值。这确实有效,但我想要原始问题的答案而不是架构更改。是的,我知道架构更改更智能。【参考方案3】:正如比尔所说,鉴于明显的 HSQL 解析器设计,不可能移除限制。
在减轻限制方面(即让自己通过将限制推到...超过 1000 个开关来达到 1000 个开关),您有两种选择。
-
在运行应用程序时增加 VM 中的堆栈大小。如果您使用的是 Sun 的 Hotspot VM,您应该能够通过例如-XX:ThreadStackSize=1024 每个线程使用 1MB 堆栈,而不是默认的 512K。这可能会让您获得更大的递归深度。
您可以在由构造函数 Thread(ThreadGroup, Runnable, String, long) 创建的线程中运行您的工作,其中最后一个参数是请求的堆栈大小。这可能有效,也可能无效;如果您阅读 Javadoc,这是一个建议——非常欢迎 VM 忽略此请求。不确定 Hotspot 的具体用途,但它可能会有所帮助。
【讨论】:
以上是关于如何在 CASE WHEN 语句中获取 HSQLDB 中超过 1000 个项目?的主要内容,如果未能解决你的问题,请参考以下文章