使用 ROWNUM 查明查询是否超过任意限制?

Find out if query exceeds arbitrary limit using ROWNUM?

我在 Oracle 中有一个存储过程,我们正在根据参数限制 ROWNUM 的记录数。但是,我们还需要知道搜索结果计数是否超过任意限制(即使我们只传递达到限制的数据;搜索可以 return 大量数据,如果超过限制用户可能想要优化他们的查询。)

限制运行良好,但我试图传递一个 OUT 值作为标志,以在超过最大结果时发出信号。我的想法是获取内部 table 的计数并将其与外部 select 查询(使用 ROWNUM)的计数进行比较,但我不确定如何将其放入变量中.有没有人这样做过?有什么方法可以做到这一点而无需 select 将所有内容都检查两次?

谢谢。

编辑:目前,我实际上正在做两个相同的 selects - 一个仅用于计数,selected 到我的变量中,另一个用于实际记录。然后我将基本结果计数的比较返回给我的最大限制参数。这意味着两个 selects,这并不理想。仍在此处寻找答案。

您可以在查询中添加一列:

select * from (
  select . . . , count(*) over () as numrows
  from . . .
  where . . .
) where rownum <= 1000;

然后上报numrows作为最终结果集的大小

您可以使用嵌套子查询:

select id, case when max_count > 3 then 'Exceeded' else 'OK' end as flag
from (
 select id, rn, max(rn) over () as max_count
 from (
    select id, rownum as rn
    from t
  )
  where rownum <= 4
)
where rownum <= 3;

内层是您的实际查询(您实际上可能有过滤器和排序子句)。中间后来限制为您的实际限制 + 1,这仍然允许 Oracle 使用停止键进行优化,并使用对该内部结果集的分析计数来查看您是否有第四条记录(不需要扫描所有匹配记录) .并且外层限制为您的原始限制。

对于包含 10 行的样本 table,得到:

        ID FLAG    
---------- --------
         1 Exceeded 
         2 Exceeded 
         3 Exceeded 

如果内部查询有一个返回较少行的过滤器,比如:

select id, rownum as rn
from t
where id < 4

它将得到:

        ID FLAG    
---------- --------
         1 OK       
         2 OK       
         3 OK       

当然对于这个演示我没有做任何排序所以你会得到不确定的结果。根据您的描述,您将使用您的变量而不是 3,并且(您的变量 + 1)而不是 4。

在我的应用程序中,我采用了一种非常简单的方法。我执行正常的 SELECT,当 returned 行数等于限制时,客户端应用程序显示 LIMIT reached 消息,因为我的查询很可能会 return 更多行,以防您不限制结果。

当然,当行数正好限制时,这是一个错误的指示。但是,在我的应用程序中,限制主要是由最终用户出于性能原因设置的,例如,典型的限制是“1000 行”或“10000 行”。

在我的例子中,这个解决方案完全足够了——而且很简单。

更新:

你知道row_limiting_clause吗?它是在 Oracle 12.1

中引入的

例如这个查询

SELECT employee_id, last_name
  FROM employees
  ORDER BY employee_id
  OFFSET 5 ROWS FETCH NEXT 10 ROWS ONLY;

将return整个结果集的第6行到第16行。它可能会帮助您找到解决方案。

另一个想法是这个:

SELECT employee_id, last_name
FROM employees
UNION ALL
SELECT NULL, NULL FROM dual
ORDER BY employee_id NULLS LAST

当您获得 employee_id IS NULL 所在的行时,您就知道您已到达结果集的末尾,不会有更多记录到达。

Select 全部,然后 select 计数和数据,限制行数。

with  
base as 
(
    select c1, c2, c3
    from table
    where condition 
) 
select (select count(*) from base), c1, c2, c3 
from base
where rownum < 100