ORA-01795:列表中的最大表达式数为1000

时间:2011-03-09 23:56:09

标签: c# arrays stringbuilder

在c#中,我们正在构建一个包含“in语句”的NHibernate查询。表达式的数量超过5000.如果我执行查询,我会收到错误。

我需要找到一种方法来打破大型字符串构建器并将它们存储在字符串构建器数组中,并在需要时执行多个查询以获得所需的输出。我们只有一个帐户拥有超过5000条记录,其余的都低于100.有人可以提出解决方法吗?

6 个答案:

答案 0 :(得分:6)

我使用的解决方案是将INOR分开。

where A in (a,b,c,d,e,f)

变为

where (A in (a,b,c) OR a in (d,e,f)) ...

这很简单,对查询格式没有特殊要求。

在我看来,这比在其他一些建议的解决方案中更容易在你的stringbuilder中实现(SQLQuerybuilder或者在你的情况下调用它)。

答案 1 :(得分:3)

您可以使用此技巧将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)

我知道它增加了查询中的'文本量',但是没有性能影响,因为无论如何都使用临时结果集而没有创建全局临时表的麻烦。

答案 2 :(得分:2)

最初的帖子问题已经过时了,但我最近已经多次遇到过这个问题并找到了可能对其他人有帮助的解决方案。而且,由于上述答案都没有给出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

这个功能我用过几种方式。一种方法是在列表分区上循环以修改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...)

答案 3 :(得分:0)

你可以创建一个临时表,用IN列表中的项填充它,然后加入它。

答案 4 :(得分:0)

您可以将选择与每个选择中的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
)

答案 5 :(得分:0)

当你在where子句中有那么多项时,可能是时候考虑重构了。

你可以创建一个存储过程,它接受一个逗号分隔的值字符串。然后,存储过程可以从该csv生成一个表,您可以与另一个表进行内连接以生成记录。

看一下这个链接,了解如何创建一个接受csv并返回一个表的函数,以便你可以查询它。

how to convert csv to table in oracle 要么 How to best split csv strings in oracle 9i