【问题标题】:Oracle LIMIT and 1000 column restrictionOracle LIMIT 和 1000 列限制
【发布时间】:2012-10-30 04:10:35
【问题描述】:

我有一个如下所示的 SQL 查询:

SELECT foo "c0",
       bar "c1",
       baz "c2",
       ...
FROM   some_table
WHERE  ...

为了应用限制,并且只返回来自该查询的记录子集,我使用以下包装 SQL:

SELECT *
FROM   (
    SELECT t.*,
           ROW_NUMBER() OVER (ORDER BY ...) rnum
    FROM   (
        ... original SQL goes here ...
    ) t
)
WHERE rnum BETWEEN 1 AND 10

我的问题是原始查询在与其他表的大量连接中选择了 1000 多个列。 Oracle 对每个表或视图有 1000 列的内部限制,显然我用来限制结果集的包装 SQL 正在创建一个应用此限制的临时视图,导致整个事情失败。

是否有另一种分页方法不会创建这样的视图,或者不会受到 1000 列限制的影响?

我对将工作分成块的建议不感兴趣,而不是选择 > 1000 列等,因为我已经完全了解所有这些方法。

【问题讨论】:

  • 选择超过 1000 列”,您的数据模型似乎有些奇怪。
  • @a_horse_with_no_name:如果说奇怪,你的意思是我有超过 1000 条关于单个实体的离散数据,这些数据对于我的特定领域都是相关且必要的,但这在整个集合中极为罕见所有域,那么你是正确的。完全没有帮助,但正确。
  • 在 30 年的数据库设计中,我从未见过需要超过 1000 列的实体。如果您的模型可以优化并因此解决问题的根本原因而不是对抗症状,我不会感到惊讶
  • 你的桌子上有钥匙吗?我猜你可以通过加入同一张表来进行分页,但只选择键列和你的 ROW_NUMBER 并在之后进行过滤。听起来不是很理想,但却是一种方式
  • @ShannonSeverance:实际上,查询是按一组唯一的列排序的,而不是 NULL(抱歉造成混淆 - 我修改了伪代码)。我尝试了其他一些不使用分析的表达式,但它们似乎都遇到了相同的列限制。

标签: sql oracle pagination


【解决方案1】:

好的,这会比你计划的更糟糕,但我的意思是你可以尝试这样的分页:

WITH CTE AS
(
    ... original SQL goes here ...
)

SELECT A.*
FROM CTE A
INNER JOIN (SELECT  YourKey,
                    ROW_NUMBER() OVER (ORDER BY ...) rnum
            FROM CTE) B
ON A.YourKey = B.YourKey
WHERE rnum BETWEEN 1 AND 10;

【讨论】:

  • 我明白了,谢谢你的回答。我尝试了这种方法,但仍然遇到相同的 1000 列限制错误。我认为这是由于这些查询使用连接数据作为子查询(Oracle 尝试创建临时视图?),因此正在应用列限制。
  • @drrcknlsn 我明白了,那么我需要自己尝试一个有 1000 列的表,看看我是否想出了一些东西
  • 为了澄清,我的表中没有一个列超过 1000 列(它们都少得多)。我只是加入了一堆不同的表,所有表中所有列的总数超过 1000。
【解决方案2】:

你不能拥有超过 1000 列的视图,所以稍微作弊。

select *
  from foo f, foo2 f2
 where (f.rowid, f2.rowid) in (select r, r2
                                 from (select r, r2, rownum rn
                                         from (select /*+ first_rows */ f.rowid r, f2.rowid r2
                                                 from foo f, foo2 f2
                                                where f.c1 = f2.a1 
                                                  and f.c2 = '1'
                                                order by f.c1))
                                where rn >= AAA
                                  and rownum <= BBB)


order by whatever;

现在将任何 where 子句放在最里面的位(例如,我放 f.c1 = '1')。

BBB = 页面大小。 AAA = 起点

【讨论】:

  • 为了澄清,这个例子中的f.c1应该是关键字段吗? order by whatever 应该是我放置结果集应该排序的列的位置吗?我是这么认为的,但是我得到的结果并不是按我放在那里的顺序排列的。我有今天的记录,我指定的第一个order by 列是修改日期,降序排列,但我看到的结果是从 2011 年开始排序的。我认为这与最里面的order by 有关。
  • 主要的顺序是在内部 sql order by f.c1 里面放你想要的任何东西(外部的逻辑上应该是相同的顺序)
  • 是的 f.c1 = f2.a1 只是连接键(你可能有几个)。正如您在示例中所说,我在那里放了两张桌子,那里有很多桌子。所以把你想要的所有表都放在那里..将它们全部加入,按照你认为合适的方式对它们进行排序..都在那个内部 sql 中。第一行提示是告诉 oracle 你只对前几个结果感兴趣(阻止它进行全面扫描,它可以避免它)。
【解决方案3】:

问题是分页还是仅返回前 10 行?如果是后者,可以这样做:

SELECT foo "c0",
       bar "c1",
       baz "c2",
       ...
FROM   some_table
WHERE  ... and
       rownum <= 10

【讨论】:

  • 这是用于分页的,所以我需要能够一次返回一页结果,从任意偏移量开始,而不仅仅是每次的前 10 个。
猜你喜欢
  • 2010-12-13
  • 1970-01-01
  • 2018-08-24
  • 1970-01-01
  • 2016-05-12
  • 1970-01-01
  • 2011-11-20
相关资源
最近更新 更多