1

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

按 val1 从选项卡组中选择 val1,count(1) cnt;

    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 计数。

例如,我在 val1 中有一个值 Item001,对应于 val1,我们在另一列 val2 中有 27 个组件。但是当我在 val1 上运行 group by 时,查询应该计算 val1 的出现次数最多 3 次,而不是超过 3 次。当计数达到 3 时,它应该停止进一步扫描表。它应该跳转到 val1 中的其他值以获取它的计数。

4

6 回答 6

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 个?)设备,每个设备每秒生成 10 条消息,这些消息被插入到按天分区的表中,并且没有索引。您想检查每个人每天至少记录 20 条消息。

一个分区的完整计数约为 1300 万行,但由于计数限制为每个设备 20 行,您实际上执行了 15 次完整分区扫描,这些扫描将在仅扫描几行后终止(通过 rownum 限制) .

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

无论如何,这只是我的想法。我并不是说这是一个好主意,但这是可能的。

于 2012-12-18T10:42:21.880 回答
1

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

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

这是因为行在表中没有排序。引擎不知道“有 item001s 和 Item002s 等”,除非您在 val1 上有一个分区表,但我几乎可以肯定这对您没有帮助。

于 2012-12-18T09:10:35.790 回答
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(非常好的服务:))

于 2012-12-18T11:43:47.217 回答
0

尽管不完全理解是你的观点,但只有 3 次......我认为你只需要计算你想要的东西的出现次数,然后你就可以执行你的 if 了,但是看看下面的链接信息是否有帮助(不知道你的Oracle版本):

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

于 2012-12-18T08:20:51.213 回答
0

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

于 2012-12-18T08:22:39.623 回答
0

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

select val1, if(cnt > 2, 3, cnt) cnt
from (select val1, count(1) cnt
from tab
group by val1) x
于 2012-12-18T08:24:06.550 回答