na przykładzie oracle bo nie mam mssqla
stworzenie tabeli
CREATE TABLE dane (
x NUMBER(10,0) NULL,
y NUMBER(10,0) NULL,
grupa NUMBER(5,0) NULL
);
wypełnienie jej 3000 losowych wartości (x, y z zakresu 1 - 1000, grupa z zakresu 1-100)
DECLARE
x NUMERIC(10, 0);
BEGIN
FOR x IN 1..3000 loop
INSERT INTO dane VALUES (Dbms_Random.Value(1, 1000), Dbms_Random.Value(1, 1000), Dbms_Random.Value(1, 100));
END LOOP;
END;
/
stworzenie tabeli uczacy i przepisanie 1000 pierwszych do tabeli uczacy
CREATE TABLE uczacy AS SELECT x, y, grupa FROM (SELECT ROWNUM rn, d.* FROM dane d) WHERE rn <= 1000;
stworzenie tabeli testowy i przepisanie pozostałych 2000 do niej
CREATE TABLE testowy AS SELECT x, y, grupa FROM (SELECT ROWNUM rn, d.* FROM dane d) WHERE rn > 1000;
czy dane są na miejscu
SELECT 'dane', Count(*) FROM dane UNION SELECT 'uczacy', Count(*) FROM uczacy UNION SELECT 'testowy', Count(*) FROM testowy;
wynik:
'DANE' |
COUNT(*) |
dane |
3000 |
testowy |
2000 |
uczacy |
1000 |
wyświetlenie każdego punktu ze zboru uczacy i wyświetlenie dla niego k (zadeklarowałem sobie 4) najbliższych ze zbioru testowy
DECLARE
CURSOR ucz IS SELECT x, y FROM uczacy WHERE ROWNUM < 10; --to jest ograniczenie, że biorę tak naprawdę tylko 10 z uczacy żeby serwera nie zajechać
TYPE test_rec IS RECORD (x NUMBER(10,0), y NUMBER(10,0), grupa NUMBER(5,0), odleglosc NUMERIC(20, 15));
TYPE test_typ IS TABLE OF TEST_REC INDEX BY PLS_INTEGER;
rec test_typ;
k NUMERIC(10, 0);
BEGIN
k := 5;
FOR u IN ucz LOOP --lecimy po wszystkich ze zbioru uczacy
SELECT --dla każdego robimy selecta, który znajduje nam k-najbliższych punktów
X, Y, grupa, odleglosc
BULK COLLECT INTO
rec
FROM
(SELECT
t.grupa,
t.X,
t.Y,
Sqrt(Power(u.X - t.X, 2) + Power(u.Y - t.Y, 2)) odleglosc --dla każdego obliczamy odległość
FROM
testowy t
ORDER BY 4) --sortujemy wg odległości rosnąco
WHERE
ROWNUM < k; --i bierzemy tylko k-pierwszych. W oraclu nie ma limit i trzeba kombinować z podzapytaniem
dbms_output.put_line('uczący (' || u.X || ', ' || u.Y || '), najbliższe:'); --linijka z info o uczącym
FOR i IN rec.first .. rec.last LOOP --i wszystkie najbliższe do niego
dbms_output.put_line(' grupa: ' || rec(i).grupa || ', (' || rec(i).x || ', ' || rec(i).y || '), odległość: ' || rec(i).odleglosc);
END LOOP;
END LOOP;
END;
wynik:
Line Pos Text
29 PL/SQL block, executed in 15 ms
uczący (664, 736), najbliższe:
grupa: 40, (664, 737), odległość: 1
grupa: 30, (675, 738), odległość: 11,180339887498948
grupa: 34, (654, 748), odległość: 15,620499351813309
grupa: 83, (643, 728), odległość: 22,472205054244232
uczący (11, 568), najbliższe:
grupa: 29, (12, 560), odległość: 8,06225774829855
grupa: 52, (16, 553), odległość: 15,811388300841897
grupa: 56, (30, 562), odległość: 19,924858845171275
grupa: 44, (33, 568), odległość: 22
uczący (829, 40), najbliższe:
grupa: 27, (824, 48), odległość: 9,433981132056604
grupa: 42, (817, 39), odległość: 12,041594578792295
grupa: 6, (820, 30), odległość: 13,45362404707371
grupa: 27, (834, 26), odległość: 14,866068747318506
uczący (121, 944), najbliższe:
grupa: 23, (118, 937), odległość: 7,615773105863908
grupa: 11, (124, 953), odległość: 9,486832980505138
grupa: 33, (139, 940), odległość: 18,439088914585775
grupa: 80, (108, 925), odległość: 23,021728866442676
uczący (252, 210), najbliższe:
grupa: 7, (251, 218), odległość: 8,06225774829855
grupa: 44, (246, 204), odległość: 8,48528137423857
grupa: 13, (244, 203), odległość: 10,630145812734649
grupa: 64, (269, 210), odległość: 17
uczący (285, 700), najbliższe:
grupa: 28, (274, 701), odległość: 11,045361017187261
grupa: 10, (291, 682), odległość: 18,973665961010276
grupa: 44, (294, 683), odległość: 19,235384061671345
grupa: 58, (276, 681), odległość: 21,023796041628638
uczący (868, 338), najbliższe:
grupa: 98, (855, 340), odległość: 13,152946437965905
grupa: 86, (881, 330), odległość: 15,264337522473748
grupa: 10, (845, 342), odległość: 23,345235059857504
grupa: 45, (886, 353), odległość: 23,430749027719963
uczący (170, 282), najbliższe:
grupa: 16, (165, 282), odległość: 5
grupa: 68, (174, 288), odległość: 7,211102550927979
grupa: 66, (166, 297), odległość: 15,524174696260024
grupa: 10, (180, 296), odległość: 17,204650534085254
uczący (847, 618), najbliższe:
grupa: 85, (855, 616), odległość: 8,246211251235321
grupa: 21, (855, 610), odległość: 11,31370849898476
grupa: 62, (839, 637), odległość: 20,615528128088303
grupa: 33, (834, 638), odległość: 23,853720883753126
Total execution time 47 ms
Czy coś jeszcze potrzeba?