如何在CASE WHEN语句中获取HSQLDB中的1000多个项目?

时间:2009-01-12 22:11:14

标签: sql hsqldb stack-overflow

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

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

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

这是非常奇怪的部分:我尝试将我的CASE声明分解成碎片,例如: 100 WHEN条款后跟ELSE ( CASE foo WHEN ... ) END。但即使进行了这次重写,我也完全采取相同的行为!

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

3 个答案:

答案 0 :(得分: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中内置的限制。

答案 1 :(得分:1)

完全消除CASE声明。

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

答案 2 :(得分:1)

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

在减轻限制方面(即通过将限制推到......超过1000的某个位置让自己达到1000个开关),你有两个选择。

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