Я использую SQL и хочу подсчитать количество точек в сетке различной размерности.
Я нашел решение, но мне интересно, может ли быть более элегантный или эффективный способ сделать это с акцентом на Oracle.
Это моя база данных:
create table tmpa (
x number(10, 2),
y number(10, 2),
val number
);
insert into tmpa values (1.0, 1.8, 9);
insert into tmpa values (1.9, 2.0, 9);
insert into tmpa values (2.1, 1.9, 9);
insert into tmpa values (2.2, 2.6, 9);
insert into tmpa values (2.6, 2.7, 9);
insert into tmpa values (3.1, 3.9, 9);
insert into tmpa values (3.4, 3.7, 9);
insert into tmpa values (3.7, 3.8, 9);
Предположим, что x
и y
правильно проиндексированы.
Это примерно соответствует точкам на плоскости.
Теперь я хочу посчитать количество точек в ячейках сетки. Сетка начинается в (xmin,ymin)
и заканчивается (xmax,ymax)
каждая, разделенная на cells
части.
Пример может выглядеть так:
| | | |
--+-------+-------+-------+-- 4.7
| | | |
| | * | |
| | * | * |
--+-------+-------+-------+-- 3.5
| | | |
| | * | |
| * | | |
--+-------+-------+-------+-- 2.3
| | | |
o | ** | | |
| | | |
--+-------+-------+-------+-- 1.1
| | | |
1.1 2.3 3.5 4.7
cells
здесь 3
, xmin
и ymin
равно 1.1
, xmax
и ymax
равно 4.7
, что приводит к размеру ячейки (dx
и dy
) из 1.2
.
Теперь я хочу посчитать количество точек в каждой ячейке. Для удобства я также могу получить центральную точку в результате запроса.
Результат будет выглядеть так:
xcell ycell COUNT center
0, 0, 2, 1.65,1.65
0, 1, 1, 1.65,2.85
1, 1, 1, 2.85,2.85
1, 2, 2, 2.85,4.05
2, 2, 1 4.05,4.05
Я бы тоже не против, чтобы в списке были указаны строки с нулем.
Это именно то, что выводит следующий запрос:
-- 1.1: xmin, 4.7: xmax, cells:3, 1.2:(xmax-xmin)/cells ; same with y
Select d2.xcell, d2.ycell, d2.cnt, d2.xcell*1.2+1.1+1.1/2 xcenter, d2.ycell*1.2+1.1+1.1/2 ycenter
From (
SELECT d1.xcell, d1.ycell, count(*) cnt
FROM (
select floor((x-1.1)/1.2) xcell, floor((y-1.1)/1.2) ycell
from tmpa
) d1
where d1.xcell>=1.1 and d1.xcell<4.7 and d1.ycell>=1.1 and d1.ycell<4.7
group by xcell, ycell
) d2
Order By d2.xcell, d2.ycell
;
Но это сложнее, чем я думал. И я не знаю, насколько это эффективно. Может быть, есть очень эффективный или очень простой запрос, который я просто не вижу.
Примечание: я не хочу использовать гео- или пространственные расширения.
Обновление: Я удалил between
, потому что >=
и <
лучше для полуоткрытых интервалов.