我有一个如下表,例如
A. 1
B. 2
C. 3
D. 99
E. 90
我需要一个查询,该查询可计算并返回最大总行数等于或小于102的行集,例如,选择总行数最接近目标的行集。
如果绑定结果的行数相同且行数相同,则采用具有最高可访问值的组合集
在此示例中,答案为A,B,D
,因为它有三个项目,而C,D
(也等于102)只有两个。
答案 0 :(得分:1)
您可以使用递归查询,但是由于这是一个非多项式问题,因此随着更多记录的出现,性能将会下降。第一个with
查询只是生成样本数据。在您的情况下,您当然会查询您的实际表:
with tbl(key, value) as (
select 'A', 1 from dual union all
select 'B', 2 from dual union all
select 'C', 3 from dual union all
select 'D', 99 from dual union all
select 'E', 90 from dual
),
rec(greatest_key, greatest_single, key_count, keys, total) as (
select key,
value,
1,
key,
value
from tbl
union all
select tbl.key,
greatest(tbl.value, rec.greatest_single),
rec.key_count+1,
substr(rec.keys, 0, 1000) || ', ' || tbl.key,
rec.total + tbl.value
from rec
inner join tbl
on tbl.key > rec.greatest_key
and rec.total + tbl.value <= 102
),
ordered(total, keys, r) as (
select total, keys, row_number() over (
order by total desc, key_count desc, greatest_single desc)
from rec
)
select total, keys
from ordered
where r = 1
ordered
部分仅用于获得“最高”记录。
看到它在rextester上运行。
如果您具有Oracle 12c +,则可以不使用ordered
来结束查询:
select total, keys
from rec
order by total desc,
key_count desc
OFFSET 0 ROWS FETCH NEXT 1 ROWS ONLY
答案 1 :(得分:0)
这是我的尝试。 未测试。
FUNCTION find_min_set ( p_target IN NUMBER ) RETURN VARCHAR2 IS
CURSOR c1 ( p_find_val NUMBER ) IS
SELECT the_id, the_val
FROM the_table t1
WHERE the_val = ( SELECT MAX( the_val ) the_val
FROM the_table
WHERE the_val <= p_find_val ) ;
l_target NUMBER;
l_id VARCHAR2(16);
l_val NUMBER;
l_ret_List VARCHAR2(4000) := '';
BEGIN
l_target := p_target;
WHILE l_target > 0 LOOP
OPEN c1 ( l_target );
FETCH c1 INTO l_id, l_val;
EXIT WHEN c1%NOTFOUND;
CLOSE c1;
l_ret_list := l_ret_list || ' ' || l_id;
l_target := l_target - l_val;
END LOOP;
l_ret_list := 'Target: ' || p_target || ',' ||
'Remaidner: ' || l_target || ', ' ||
'List: ' || l_ret_list;
RETURN ( l_ret_list );
END;
/
查询返回最大值<=目标的col。 从目标中减去返回的值,然后我们再次搜索最大值<=新目标。 我们重复此过程,直到新目标为0(已达到原始标记)或没有其他值<=目标为止。 根据需要形成结果并返回。