我有一个要求,我需要在ArrayList中找到第一个缺少的数字,而数据库(Oracle)列中没有这个数字。
情景是这样的:
表1:
从上表中我想制作3个列表
List<Integer> lst1 = new ArrayList<Integer>();
List<Integer> lst2 = new ArrayList<Integer>();
List<Integer> lst3 = new ArrayList<Integer>();
lst1 - &gt; [0,1,2,3,4,5,6 .... 1000]
lst2 - &gt; [A0,A1,A2,A3,A4,A5,A6 .... A1000]
lst3 - &gt; [B0,B1,B2,B3,B4,B5,B6 .... B1000]
截至目前,列表中包含大约1000个序列顺序值。
现在我有一个数据库表,如下所示
如何将lsts与Range列匹配。 我需要找到这个表中没有来自lsts的值?
就像在这种情况下,如果我们从“lst1”看到表中没有的第一个可用值是“1”,那么下一个可用值是“3”然后是5.6 ......等等。 类似地,对于“lst2”,第一个缺失值是“a3”
有什么办法吗?
答案 0 :(得分:1)
以下查询获取range_start和range_end的前缀和数值 为了简化示例,我将范围限制为0-5
SELECT lstname,
regexp_substr( rangestart, '[^0-9]') AS Prefix,
regexp_substr( rangestart, '[0-9]') AS r_start,
regexp_substr( rangeend, '[0-9]') AS r_end
FROM table_1
LSTNAME |PREFIX |R_START |R_END |
--------|-------|--------|------|
Lst1 | |0 |5 |
Lst2 |a |0 |5 |
Lst3 |b |0 |5 |
以下查询将使用上述查询作为子查询生成范围的所有值
请注意CROSS JOIN LATERAL
适用于Oracle 12c及更高版本,如果您使用的是早期版本,则必须重写此查询。
SELECT lstname, prefix || val AS val
FROM (
SELECT lstname,
regexp_substr( rangestart, '[^0-9]') AS Prefix,
regexp_substr( rangestart, '[0-9]') AS r_start,
regexp_substr( rangeend, '[0-9]') AS r_end
FROM table_1
) x
CROSS JOIN LATERAL (
SELECT LEVEL - 1 + x.r_start AS val
FROM dual
CONNECT BY LEVEL <= x.r_end - x.r_start + 1
)
LSTNAME |VAL |
--------|----|
Lst1 |0 |
Lst1 |1 |
Lst1 |2 |
Lst1 |3 |
Lst1 |4 |
Lst1 |5 |
Lst2 |a0 |
Lst2 |a1 |
Lst2 |a2 |
Lst2 |a3 |
Lst2 |a4 |
Lst2 |a5 |
Lst3 |b0 |
Lst3 |b1 |
Lst3 |b2 |
Lst3 |b3 |
Lst3 |b4 |
Lst3 |b5 |
现在说table_2
包含以下值:
SELECT * FROM table_2
RANGE |
------|
3 |
a0 |
a1 |
a5 |
b3 |
b4 |
b5 |
要查找缺失值,只需将上述查询LEFT JOIN到此表并过滤掉非空值
请注意,我在引号中使用"RANGE"
作为此示例中的列名,因为RANGE
是Oracle中的保留字
SELECT lstname, val
FROM (
SELECT lstname, prefix || val AS val
FROM (
SELECT lstname,
regexp_substr( rangestart, '[^0-9]') AS Prefix,
regexp_substr( rangestart, '[0-9]') AS r_start,
regexp_substr( rangeend, '[0-9]') AS r_end
FROM table_1
) x
CROSS JOIN LATERAL (
SELECT LEVEL - 1 + x.r_start AS val
FROM dual
CONNECT BY LEVEL <= x.r_end - x.r_start + 1
)
) XX
LEFT JOIN table_2 t2
ON t2."RANGE" = xx.val
WHERE t2."RANGE" IS NULL
ORDER BY 1, 2;
LSTNAME |VAL |
--------|----|
Lst1 |0 |
Lst1 |1 |
Lst1 |2 |
Lst1 |4 |
Lst1 |5 |
Lst2 |a2 |
Lst2 |a3 |
Lst2 |a4 |
Lst3 |b0 |
Lst3 |b1 |
Lst3 |b2 |
此版本的子查询模拟了横向连接,应该可以在Oracle 10上运行,但我还没有测试过它
SELECT lstname,
prefix || column_value AS val
FROM (
SELECT lstname,
regexp_substr( rangestart, '[^0-9]') AS Prefix,
regexp_substr( rangestart, '[0-9]') AS r_start,
regexp_substr( rangeend, '[0-9]') AS r_end
FROM table_1
) x
CROSS JOIN table(cast(multiset(
SELECT LEVEL - 1 + x.r_start AS val
FROM dual
CONNECT BY LEVEL <= x.r_end - x.r_start + 1
) as sys.OdciNumberList)) q
;