上面说的第三步必须保证每个点不能重复分配,有些难度,还是用过程代码吧。
CREATE TABLE t_offset as
select 1 id,1.001 x,1.002 y, 10 mark from dual
union all
select 2011 id,1.001 x,1.012 y, 31 mark from dual
union all
select 34213 id,2.009 x,2.504 y, 51 mark from dual
union all
select 42 id,1.001 x,1.002 y, 92 mark from dual
union all
select 555 id,1.001 x,1.002 y, 71 mark from dual
union all
select 678 id,3.122 x,4.998 y, 43 mark from dual
union all
select 730 id,7.010 x,1.111 y, 11 mark from dual
;
CREATE INDEX t_offset_idx ON t_offset(x,y);
CREATE TYPE obj_dots AS OBJECT (id NUMBER,x number,y NUMBER);
/
CREATE TYPE t_obj_dots AS TABLE OF obj_dots;
/
DECLARE
lv_dots t_obj_dots:=t_obj_dots();
lv_level NUMBER;
BEGIN
FOR lv_dup IN
( SELECT *
FROM (SELECT t_offset.*
,ROW_NUMBER() OVER(PARTITION BY x,y ORDER BY id) rn
FROM t_offset
)
WHERE rn>1
)
LOOP
lv_level :=1;
WHILE lv_level>0 LOOP
FOR lv_new IN
( SELECT *
FROM (SELECT off_x
,off_y
,lv_dup.x + off_x*0.001 x
,lv_dup.y + off_y*0.001 y
FROM (SELECT LEVEL-lv_level-1 off_x FROM DUAL CONNECT BY LEVEL<=lv_level*2+1)
,(SELECT LEVEL-lv_level-1 off_y FROM DUAL CONNECT BY LEVEL<=lv_level*2+1)
WHERE off_x IN (lv_level,-lv_level) OR off_y IN (lv_level,-lv_level)
)
WHERE (x,y) NOT IN (SELECT x,y FROM t_offset)
AND (x,y) NOT IN (SELECT x,y FROM TABLE(lv_dots))
ORDER BY off_x*off_x+off_y*off_y
)
LOOP
lv_dots.EXTEND;
lv_dots(lv_dots.COUNT):=obj_dots(lv_dup.id,lv_new.x,lv_new.y);
lv_level := -999;
EXIT;
END LOOP;
lv_level := lv_level+1;
END LOOP;
END LOOP;
FOR i IN 1..lv_dots.COUNT LOOP
DBMS_OUTPUT.PUT_LINE('id:'||lv_dots(i).id||' x:'||lv_dots(i).x||' y:'||lv_dots(i).y);
END LOOP;
END;
/