我正在尝试比较测试表和参考表之间的整数值范围。如果测试表中的任何值范围与参考表中的可用范围重叠,则应将其删除。
很抱歉,虽然不清楚,但是下面是示例数据:
TEST_TABLE:
MIN MAX
10 121
122 648
1200 1599
REFERENCE_TABLE:
MIN MAX
50 106
200 1400
1450 1500
修改后的测试表:(运行PL / SQL后的预期结果)
MIN MAX
10 49
107 121
122 199
1401 1449
1501 1599
在上面示例的第一行中,将10-121分为两行:10-49和107-121,因为值50、51,...,106包含在reference_table(50-106);等等。
这是到目前为止我用嵌套循环编写的内容。我创建了两个额外的临时表,这些临时表将存储在引用表中可以找到的所有值。然后它将创建要插入到test_table的新范围集。
但这似乎无法正常工作,并且 可能会导致性能问题,尤其是当我们要处理数百万甚至更高的值时:
CREATE TABLE new_table (num_value NUMBER);
CREATE TABLE new_table_next (num_value NUMBER, next_value NUMBER);
-PL / SQL启动
DECLARE
l_count NUMBER;
l_now_min NUMBER;
l_now_max NUMBER;
l_final_min NUMBER;
l_final_max NUMBER;
BEGIN
FOR now IN (SELECT min_num, max_num FROM test_table) LOOP
l_now_min:=now.min_num;
l_now_max:=now.max_num;
WHILE (l_now_min < l_now_max) LOOP
SELECT COUNT(*) -- to check if number is found in reference table
INTO l_count
FROM reference_table refr
WHERE l_now_min >= refr.min_num
AND l_now_min <= refr.max_num;
IF l_count > 0 THEN
INSERT INTO new_table (num_value) VALUES (l_now_min);
COMMIT;
END IF;
l_now_min:=l_now_min+1;
END LOOP;
INSERT INTO new_table_next (num_value, next_value)
VALUES (SELECT num_value, (SELECT MIN (num_value) FROM new_table t2 WHERE t2.num_value > t.num_value) AS next_value FROM new_table t);
DELETE FROM test_table t
WHERE now.min_num = t.min_num
AND now.max_num = t.max_num;
COMMIT;
SELECT (num_value + 1) INTO l_final_min FROM new_table_next;
SELECT (next_value - num_value - 2) INTO l_final_max FROM new_table_next;
INSERT INTO test_table (min_num, max_num)
VALUES (l_final_min, l_final_max);
COMMIT;
DELETE FROM new_table;
DELETE FROM new_table_next;
COMMIT;
END LOOP;
END;
/
请帮助,我被困住了。 :)
答案 0 :(得分:1)
此方法背后的想法是展开两个表,并跟踪数字是在参考表中还是在原始表中。这确实很麻烦,因为相邻的值可能会引起问题。
然后,我们的想法是在两个维度上都执行“间隙和孤岛”类型的解决方案-然后仅保留原始表中的值,而不保留第二个表中的值。也许这可以称为“排他性孤岛与孤岛”。
这是一个有效的版本:
public void InitializeLevelUp()
{
StartCoroutine(LevelUp());
}
public IEnumerator LevelUp()
{
playerLevelText.text = ("You have gained a level!");
strenghtAttribute++;
intellectAttribute++;
playerLevel++;
yield return new WaitForSeconds(2f);
playerLevelText.text = "";
//alternatively, set the text object inactive
}
here是db <>小提琴。
获得重叠的反问题要容易得多。将参考表“反转”以进行处理可能是可行的。
with vals as (
select min as x, 1 as inc, 0 as is_ref
from test_table
union all
select max + 1, -1 as inc, 0 as is_ref
from test_table
union all
select min as x, 0, 1 as is_ref
from reference_table
union all
select max + 1 as x, 0, -1 as is_ref
from reference_table
)
select min, max
from (select refgrp, incgrp, ref, inc2, min(x) as min, (lead(min(x), 1, max(x) + 1) over (order by min(x)) - 1) as max
from (select v.*,
row_number() over (order by x) - row_number() over (partition by ref order by x) as refgrp,
row_number() over (order by x) - row_number() over (partition by inc2 order by x) as incgrp
from (select v.*, sum(is_ref) over (order by x, inc) as ref,
sum(inc) over (order by x, inc) as inc2
from vals v
) v
) v
group by refgrp, incgrp, ref, inc2
) v
where ref = 0 and inc2 = 1 and min < max
order by min;
答案 1 :(得分:1)
这是从我在Teradata上执行的类似任务(使用日期而不是数字)修改而成的,它基于与Gordon相同的基础数据(所有开始/结束值组合在一个列表中),但是使用了更简单的逻辑:
function update(p1,p2) {
const c=document.getElementById("screen");
const ctx=c.getContext("2d");
requestAnimationFrame(update); // calls the inner update to start the animation
function update() { // this inner function remebers variables from the outer function
// which is called closing over, or closure.
// That means that p1,p2, c, and ctx are remembered by this function
// as long as it keeps calling requestAnimationFrame(update)
clearCanvas(ctx);
p1.movement();
p2.movement();
p1.draw(ctx);
p2.draw(ctx);
p1.removeBlast();
p2.removeBlast();
for(i=0;i<p1.blastCount;i++)
{
p1.blastList[i].draw(ctx);
}
for(i=0;i<p2.blastCount;i++)
{
p2.blastList[i].draw(ctx);
}
requestAnimationFrame(update); // calls the inner function
}
}
请参见db-fiddle
答案 2 :(得分:0)
这是执行此操作的一种方法。我将测试数据放在WITH子句中,而不是创建表(我发现这样做更容易进行测试)。我使用了您的列名(MIN和MAX);但是,这些都是非常差的选择,因为MIN和MAX是Oracle关键字。它们肯定会引起混乱,并且可能导致查询错误。
策略很简单-首先对REFERENCE_TABLE中的范围进行补全,这也将是间隔的并集(使用NULL作为负无穷大和正无穷大的标记);然后将TEST_TABLE中的每个间隔与REFERENCE_TABLE的补码中的每个间隔相交。下面的解决方案的最终(外部)查询中显示了如何完成此操作。
with
test_table (min, max) as (
select 10, 121 from dual union all
select 122, 648 from dual union all
select 1200, 1599 from dual
)
, reference_table (min, max) as (
select 50, 106 from dual union all
select 200, 1400 from dual union all
select 1450, 1500 from dual
)
,
prep (min, max) as (
select lag(max) over (order by max) + 1 as min
, min - 1 as max
from ( select min, max from reference_table
union all
select null, null from dual
)
)
select greatest(t.min, nvl(p.min, t.min)) as min
, least (t.max, nvl(p.max, t.max)) as max
from test_table t inner join prep p
on t.min <= nvl(p.max, t.max)
and t.max >= nvl(p.min, t.min)
order by min
;
MIN MAX
---------- ----------
10 49
107 121
122 199
1401 1449
1501 1599
答案 3 :(得分:0)
解决问题的示例:
CREATE TABLE xrange_reception
(
vdeb NUMBER,
vfin NUMBER
);
CREATE TABLE xrange_transfert
(
vdeb NUMBER,
vfin NUMBER
);
CREATE TABLE xrange_resultat
(
vdeb NUMBER,
vfin NUMBER
);
insert into xrange_reception values (10,50);
insert into xrange_transfert values (15,25);
insert into xrange_transfert values (30,33);
insert into xrange_transfert values (40,45);
DECLARE
CURSOR cr_rec IS SELECT * FROM xrange_reception;
CURSOR cr_tra IS
SELECT *
FROM xrange_transfert
ORDER BY vdeb;
i NUMBER;
vdebSui NUMBER;
BEGIN
FOR rc IN cr_rec
LOOP
i := 1;
vdebSui := NULL;
FOR tr IN cr_tra
LOOP
IF tr.vdeb BETWEEN rc.vdeb AND rc.vfin
THEN
IF i = 1 AND tr.vdeb > rc.vdeb
THEN
INSERT INTO xrange_resultat (vdeb, vfin)
VALUES (rc.vdeb, tr.vdeb - 1);
ELSIF i = cr_rec%ROWCOUNT AND tr.vfin < rc.vfin
THEN
INSERT INTO xrange_resultat (vdeb, vfin)
VALUES (tr.vfin, rc.vfin);
ELSIF vdebSui < tr.vdeb
THEN
INSERT INTO xrange_resultat (vdeb, vfin)
VALUES (vdebSui + 1, tr.vdeb - 1);
END IF;
vdebSui := tr.vfin;
i := i + 1;
END IF;
END LOOP;
IF vdebSui IS NOT NULL THEN
IF vdebSui < rc.vfin
THEN
INSERT INTO xrange_resultat (vdeb, vfin)
VALUES (vdebSui + 1, rc.vfin);
END IF;
ELSE
INSERT INTO xrange_resultat (vdeb, vfin)
VALUES (rc.vdeb, rc.vfin);
END IF;
END LOOP;
END;
所以:
表xrange_reception:
vdeb vfin
10 50
表xrange_transfert:
vdeb vfin
15 25
30 33
40 45
表xrange_resultat:
vdeb vfin
10 14
26 29
34 39
46 50