限制组中的计数

时间:2012-12-18 08:16:48

标签: sql oracle group-by oracle11g

我有查询与获取col1中特定值的计数有关。但我有兴趣将计数限制为3,因为在我的程序逻辑中,我正在执行IF条件:

选择val1,count(1)cnt 来自标签 按val1分组;

    IF cnt=0
       --do something
    ELSIF cnt=1
      --do something
    ELSIF cnt=2
      --do something
    ELSIF cnt>2
      --do something
    ELSE
      --do something
    END IF;

我不想继续计算出现超过2的值,因为它在这么大的桌子上会产生额外的开销' TAB'。

我想要数到3,然后告诉oracle再停止计数val1。

e.g。我在val1中有一个值Item001,对应于val1,我们在另一列val2中有27个组件。但是当我在val1上运行group by时,查询应该将val1的出现次数计算到3,而不是高于3。它应该在达到计数3时再停止扫描表。它应该跳转到val1中的其他值以获得计数。

6 个答案:

答案 0 :(得分:3)

我认为有一组有限的情况值得这样做,但是假设我们确实有一个带有ID列的表T1,以及另一个带有ID值的表T2,而且你只想计算最多3次。

你可能会尝试的是:

 select id,
        (select count(*) from t2 where t2.id = t1.id and rownum <= 3) c_star
 from   t1

http://sqlfiddle.com/#!4/1ab50/1/0

但是你应该根据更常规的计数方法确定基准。

编辑:只考虑可能比完整计数更快的情况。

假设您有少量(15?)设备,每个设备每秒生成十条消息,这些消息将插入到按日分区的表中,并且未编入索引。你想检查每个人每天至少记录20条消息。

分区的完整计数大约为1300万行,但由于每个设备的计数限制为20行,因此实际执行15次完整分区扫描,这些扫描全部将在几行之后终止(通过rownum限制)已扫描过。

当然,如果您的设备出现故障,您最终会进行全面扫描。

无论如何,这只是我的头顶。我不是说这是一个好主意,但它是可能的。

答案 1 :(得分:1)

您应该了解Oracle如何读取数据。

引擎要求磁盘上的数据块。它不知道下一个街区是什么。例如,它不知道是否有更多“Item001”或有新项目。它应该读取块 - 其中的所有行。然后,再计算一个Item001s或Item999s与从磁盘获取块所需的时间相比没什么。

这是因为表中没有排序行。引擎不知道'有item001s并且有Item002s等',除了你在val1上有一个分区表,但我几乎肯定这对你没用。

答案 2 :(得分:0)

尽管不完全理解是你的点数只有3 ...我认为你只需要计算你想要的事件然后你可以执行你的if,但是看看是否有以下链接信息可以提供帮助(不知道您的Oracle版本):

http://www.orafaq.com/faq/how_does_one_select_the_top_n_rows_from_a_table

答案 3 :(得分:0)

您可以使用rownum将行限制为最多3。 如果您使用此选项,那么您的选择将在第3行之后停止,因此您不会计算100000行。

答案 4 :(得分:0)

要将计数限制为3,请执行以下操作:

select val1, if(cnt > 2, 3, cnt) cnt
from (select val1, count(1) cnt
from tab
group by val1) x

答案 5 :(得分:0)

猜猜我不是疯了:) 品尝它。

select mgr, (next_empno + next2_empno + 1) cnt 
from (
  SELECT empno, mgr,
    FIRST_VALUE(empno) OVER (PARTITION BY mgr ORDER BY empno) first_empno,
    LEAD(SIGN(empno), 1, 0) OVER (PARTITION BY mgr ORDER BY empno) next_empno,
    LEAD(SIGN(empno), 2, 0) OVER (PARTITION BY mgr ORDER BY empno) next2_empno
  FROM emp
)
where first_empno = empno

它使用的是标准方案,但这里是 SQLFiddle(非常好的服务:))