Oracle 错误代码 ORA-00913 - IN CLAUSE 限制超过 65000 个值(每 1k 个值使用 OR 条件)
Oracle error code ORA-00913 - IN CLAUSE limitation with more than 65000 values (Used OR condition for every 1k values)
我的应用程序团队正在尝试使用他们的程序动态构建的 SELECT 查询从 table 中获取 85,000 个值。
SELECT * FROM TEST_TABLE
WHERE (
ID IN (00001,00002, ..., 01000)
OR ID IN (01001,01002, ..., 02000)
...
OR ID IN (84001,84002, ..., 85000)
));
但我收到错误消息“ORA-00913 值太多”。
如果我将 in 子句减少到只有 65,000 个值,我就不会收到此错误。 IN CLAUSE(带OR子句)有取值限制吗
问题不在于 in
列表;它是关于 or
分隔复合条件的数量限制。我相信该限制不适用于 or
,而是适用于使用 or
、and
和 not
的任意组合的任何复合条件,有或没有括号。而且,重要的是,这似乎没有在任何地方记录,也没有被 Oracle 的任何人承认。
您已经清楚地知道,in
列表中有 1000 个项目的限制 - 您已经解决了这个问题。
解析器将 in
条件扩展为复合的 or
分隔条件。适用于您的限制是我已经提到的限制。
限制为 65,535 个“原子”条件(与 or
、and
、not
放在一起)。不难写出证实这一点的例子。
更好的问题是为什么(当然,还有如何解决它)。
我的怀疑:要评估这种复合条件,编译后的代码必须使用堆栈,这很可能是作为数组实现的。该数组由无符号的 16 位整数索引(为什么这么小,只有 Oracle 知道)。所以堆栈大小不能超过 2^16 = 65,536;实际上只少了一个,因为 Oracle 认为数组索引从 1 开始,而不是从 0 开始——所以它们丢失了一个索引值 (0)。
解决方法:创建一个临时 table 来存储您的 85,000 个值。请注意,使用元组(人工的)的想法允许您克服单个 in
列表的 1000 个值限制,但它确实 not 绕过限制or
分隔的复合条件中的 65,535 个“原子”条件;此限制适用于最一般的情况,无论条件最初来自何处(in
列表或其他任何内容)。
有关 AskTom 的更多信息 - 您可能想从底部开始(我的评论,是线程中的最后一个):
我的应用程序团队正在尝试使用他们的程序动态构建的 SELECT 查询从 table 中获取 85,000 个值。
SELECT * FROM TEST_TABLE
WHERE (
ID IN (00001,00002, ..., 01000)
OR ID IN (01001,01002, ..., 02000)
...
OR ID IN (84001,84002, ..., 85000)
));
但我收到错误消息“ORA-00913 值太多”。
如果我将 in 子句减少到只有 65,000 个值,我就不会收到此错误。 IN CLAUSE(带OR子句)有取值限制吗
问题不在于 in
列表;它是关于 or
分隔复合条件的数量限制。我相信该限制不适用于 or
,而是适用于使用 or
、and
和 not
的任意组合的任何复合条件,有或没有括号。而且,重要的是,这似乎没有在任何地方记录,也没有被 Oracle 的任何人承认。
您已经清楚地知道,in
列表中有 1000 个项目的限制 - 您已经解决了这个问题。
解析器将 in
条件扩展为复合的 or
分隔条件。适用于您的限制是我已经提到的限制。
限制为 65,535 个“原子”条件(与 or
、and
、not
放在一起)。不难写出证实这一点的例子。
更好的问题是为什么(当然,还有如何解决它)。
我的怀疑:要评估这种复合条件,编译后的代码必须使用堆栈,这很可能是作为数组实现的。该数组由无符号的 16 位整数索引(为什么这么小,只有 Oracle 知道)。所以堆栈大小不能超过 2^16 = 65,536;实际上只少了一个,因为 Oracle 认为数组索引从 1 开始,而不是从 0 开始——所以它们丢失了一个索引值 (0)。
解决方法:创建一个临时 table 来存储您的 85,000 个值。请注意,使用元组(人工的)的想法允许您克服单个 in
列表的 1000 个值限制,但它确实 not 绕过限制or
分隔的复合条件中的 65,535 个“原子”条件;此限制适用于最一般的情况,无论条件最初来自何处(in
列表或其他任何内容)。
有关 AskTom 的更多信息 - 您可能想从底部开始(我的评论,是线程中的最后一个):