输入查询值: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
它给了我数,但我不知道如何将行压缩为三行。
我无法添加完整的查询,我一直收到'提交时发生错误'。由于某种原因,它不喜欢union子句。所以我将查询附加为图像:(
确切要求的更多细节:
我正在编写一个ip管理模块,我需要在ip块中找到可用的(免费)ip地址。阻止可以是/ 16或/ 24或甚至/ 12。为了使它更具挑战性,我也支持IPv6,因此需要管理更多数字。所有已发布的IP地址都以十进制格式存储。所以我的想法是首先在从网络地址到广播地址的块范围内生成所有ip小数。例如。在/ 24中,有255个地址,如果是/ 16则是64K。
现在,其次,查找一个块中的所有已使用的地址,并找到具有启动ip的可用地址数。因此在上面的示例中,可以启动1个ip-3地址,从6,9开始可用。
我最后一个问题是查询应该能够以足够快的速度运行以运行数百万个数字。
再次抱歉,如果我的原始问题不够明确。
答案 0 :(得分:3)
您尝试过的类似想法:
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与您的CTE基本相同,在这种情况下生成起始值和结束值之间的所有数字 - 1到20(包括!)。
missing_values
CTE会移除表格中的值,因此您将1,2,3,6,7,8,9,10,11,12,13,14,17,18,19,20
留下。
chains
CTE扮演了神奇的角色。这将获得每个值与您期望它在连续列表中的位置之间的差异。不同之处 - 我所谓的“链条”和#39; - 对于所有连续的缺失值都是相同的; 1,2,3全部获得0,6到14全部获得2,17到20全部获得4.然后可以使用该链值进行分组,并且您可以使用聚合计数和分钟来获得所需的答案
SQL Fiddle of a simplified version专门针对1-20,显示每个中间步骤的数据。这可以适用于任何上限,只需更改20,但假设您始终从1开始。