ORA-01795:列表中的最大表达式数为1000
在c#中,我们正在为NHibernate构建一个包含“in语句”的查询。 表达式的数量超过5000.如果我执行查询,我会收到错误。
我需要找到一种方法来打破大型字符串构建器并将它们存储在字符串构建器数组中,并在需要时执行多个查询以获得所需的输出。 我们只有一个帐户拥有超过5000条记录,其余的都低于100.有人可以提出解决方法吗?
我使用的解决方案是用OR
分割IN
。
where A in (a,b,c,d,e,f)
变
where (A in (a,b,c) OR a in (d,e,f)) ...
这很简单,对查询格式没有特殊要求。
在我看来,这比在其他一些建议的解决方案中更容易在您的stringbuilder(SQLQuerybuilder或其他情况下调用)中实现。
您可以使用此技巧将IN转换为JOIN
SELECT * FROM maintable JOIN ( SELECT v1 a FROM DUAL UNION ALL SELECT v2 a FROM DUAL UNION ALL SELECT v3 a FROM DUAL UNION ALL ... SELECT v2000 a FROM DUAL) tmp on tmp.a = maintable.id
此查询与
SELECT * FROM maintable WHERE id IN (v1, v2, v3, ...., v2000)
我知道它增加了查询中的“文本量”,但是没有性能影响,因为无论如何都使用临时结果集而没有创建全局临时表的麻烦。
最初的post问题已经过时了,但我最近几次遇到过这个问题,并找到了一个可能对其他人有帮助的解决方案。 并且,由于以上答案都没有给出NHibernate代码的答案,我也认为这与post相关。
在我们的软件产品中,用户可以在用户界面中进行选择。 然后,前端将相应id的列表传递给后端,以进行数据查询和操作。
首先,我需要一个函数将元素列表拆分为1000个元素的分区。
注意,这是VB.NET,但函数本身在C#中的StackOverflow上的其他位置找到:
Public Shared Iterator Function Partition(Of T)(source As IList(Of T), Optional size As Int32 = 1000) As IEnumerable(Of List(Of T)) For i As Integer = 0 To CInt(Math.Ceiling(source.Count / CDbl(size))) Yield New List(Of T)(source.Skip(size * i).Take(size)) Next End Function
这个function我用过几种方式。 一种方法是在列表分区上循环以修改QueryOver以生成所有部分结果的联合,如下所示:
Dim allPartitions As IEnumerable(Of List(Of Integer)) = Partition(idList, SplitSize) Dim foundObjects As IEnumerable(Of MyEntity) = New List(Of MyEntity) For Each part As List(Of Integer) In allPartitions foundObjects = foundObjects.Union( _session.QueryOver(Of MyEntity) _ WhereRestrictionOn(Function(x) x.ID).IsIn(part).Future()) Next
我使用它的另一种方法是创建一个可以在QueryOvers中应用的限制。 以下函数创建了这样的限制(ICriterion):
Public Shared Function GetRestrictionOnIds(ids As List(Of Integer), propertyName As String) As ICriterion Dim allParts As IEnumerable(Of List(Of Integer)) = Partition(ids, SplitSize) Dim restriction As Disjunction = Restrictions.Disjunction() For Each part As List(Of Integer) In allParts restriction.Add(Restrictions.In(propertyName, part)) Next Return Restrictions.Conjunction().Add(restriction) End Function
我把这个函数称为:
Dim wellIdRestriction As ICriterion = GetRestrictionOnIds(wellIdsList, "WellId") Dim bleedOffs As IList(Of BleedOff) = _session.QueryOver(Of BleedOff)() _ .Where(wellIdRestriction) _ .Where(..... more restrictions...) _ .And(...yet more restrictions....) _ .List().GroupBy(...some function...) _ .ToDictionary(.. key-function, value-function...)
您可以创建临时表,使用IN列表中的项填充它,然后加入它。
您可以将选择与每个选择中的1000个IN组合在一起。 不像创建临时表那样高效,但对于临时查询,它可以工作。
SELECT A, B, C from BLAH WHERE A IS IN ( 0 - 999 ) UNION SELECT A, B, C from BLAH WHERE A IS IN ( 1000 - 1999 )
当你在where子句中有那么多项时,可能是时候考虑重构了。
你可以创建一个存储过程,它接受一个逗号分隔的值字符串。 然后,存储过程可以从该csv生成一个表,您可以与另一个表进行内连接以生成记录。
看看这个链接,了解如何创建一个接受csv的函数并返回一个表,以便您可以查询它。
如何在oracle中将csv转换为表或如何在oracle 9i中最好地拆分csv字符串