【问题标题】:Oracle query to count rows based on value from next recordOracle查询根据下一条记录的值计算行数
【发布时间】:2015-02-25 21:19:10
【问题描述】:

查询的输入值:1-20 数据库中的值:4,5, 15,16

我想要一个查询结果如下

Value - Count
===== - =====
1     - 3    
6     - 9
17    - 3

所以基本上,首先生成从 1 到 20 的连续数字,计算可用数字。 我写了一个查询,但我不能让它完全工作:

with avail_ip as (
      SELECT (0) + LEVEL AS val
      FROM DUAL
      CONNECT BY LEVEL < 20),
  grouped_tab as (
  select val,lead(val,1,0) over (order by val) next_val 
  from avail_ip u
  where not exists (
    select 'x' from (select 4 val from dual) b
    where b.val=u.val)  )
  select 
    val,next_val-val difference,
    count(*) over (partition by next_val-val) avail_count
  from grouped_tab
  order by 1

它给了我计数,但我不确定如何将行压缩为三行。

我无法添加完整的查询,我不断收到“提交时出错”。由于某种原因,它不喜欢联合条款。所以我将查询附加为图像:(

具体要求的更多细节:

我正在编写一个 ip 管理模块,我需要在一个 ip 块中找出可用(免费)的 ip 地址。块可以是 /16 或 /24 甚至 /12。为了使它更具挑战性,我还支持 IPv6,因此将有更多的数字需要管理。所有发布的 IP 地址都以十进制格式存储。所以我的想法是首先生成从网络地址到广播地址的块范围内的所有ip小数。例如。在 /24 中,将有 255 个地址,在 /16 中将有 64K。

现在,其次查找块内所有已使用的地址,并找出具有起始ip的可用地址数。所以在上面的例子中,起始1个ip-3个地址可用,起始6个,9个可用。

我最后担心的是查询应该能够以足够快的速度运行以遍历数百万个数字。

再次抱歉,如果我最初的问题不够清楚。

【问题讨论】:

    标签: oracle11g


    【解决方案1】:

    与您尝试过的想法类似:

    with all_values as (
      select :start_val + level - 1 as val
      from dual
      connect by level <= (:end_val - :start_val) + 1
    ),
    missing_values as (
      select val
      from all_values
      where not exists (select null from t42 where id = val)
    ),
    chains as (
      select val,
        val - (row_number() over (order by val) + :start_val - 1) as chain
      from missing_values
    )
    select min(val), count(*) - 1 as gap_count
    from chains
    group by chain
    order by min(val);
    

    start_val 为 1,end_val 为 20,表 t42 中的数据得到:

      MIN(VAL)  GAP_COUNT
    ---------- ----------
             1          3 
             6          9 
            17          4 
    

    我已经将end_val 包含在内;不确定您是否希望它具有包容性或排他性。而且我可能已经根据您的需要使其更加灵活 - 您的版本还假设您始终从 1 开始。

    all_values CTE 与您的基本相同,在本例中生成开始值和结束值之间的所有数字 - 1 到 20(包括!)。

    missing_values CTE 删除表中的值,因此您只剩下1,2,3,6,7,8,9,10,11,12,13,14,17,18,19,20

    chains CTE 发挥了神奇的作用。这会得到每个值与您期望它在连续列表中的位置之间的差异。区别——我称之为“链”——对于所有连续的缺失值都是一样的; 1,2,3 都得 0,6 到 14 都得 2,17 到 20 都得 4。然后可以使用该链值进行分组,您可以使用聚合计数和最小值来获得您需要的答案.

    SQL Fiddle of a simplified version 专门针对 1-20,显示来自每个中间步骤的数据。这适用于任何上限,只需更改 20,但假设您总是从 1 开始。

    【讨论】:

    • 太完美了!正是我需要的。和出色的解释。很抱歉我的原始问题缺乏细节,因为由于某种原因我很难添加我的查询。让我问你一下。这个查询是否足以处理来自第一个查询的超过一百万个数字?你知道我将为我的原始问题添加更多详细信息。
    猜你喜欢
    • 1970-01-01
    • 2023-01-25
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多