Как запросить те же объекты рядом с ech other из таблицы с 2d координатами? - PullRequest
0 голосов
/ 22 сентября 2018

В последнее время я потратил много времени, пытаясь выяснить проблему выбора группы предметов с одинаковым атрибутом, которые находятся рядом друг с другом.У меня есть такие столбцы:

Lp.атр.х корр.y высота ширины кокса Вот примерные данные (x, y - координаты левого нижнего угла прямоугольника):

CREATE TABLE example_rect (
id int NULL,
attr varchar(5) NULL,
x numeric(5,2) NULL,
y numeric(5,2) NULL,
height numeric(5,2) NULL,
width numeric(5,2) NULL
);

INSERT INTO example_rect (id,attr,x,y,height,width) VALUES 
(1,'A',0.36,43.60,7.15,5.72)
,(2,'A',0.50,35.60,7.15,4.65)
,(3,'A',0.88,26.75,6.00,4.25)
,(4,'B',5.50,36.00,6.75,5.15)
,(5,'B',6.25,43.35,8.40,5.51)
,(6,'C',6.60,25.95,7.80,4.93)
,(7,'B',11.50,36.00,6.75,5.15)
,(8,'B',12.25,43.35,8.40,5.51)
,(9,'C',12.60,25.95,7.80,4.93)
,(10,'E',17.19,34.67,8.08,5.53)
,(11,'D',18.45,25.92,7.83,5.18)
,(12,'A',18.78,44.04,6.71,4.45)
,(13,'E',23.19,34.67,8.08,5.53)
,(14,'A',23.78,44.04,6.71,4.45)
,(15,'D',24.50,27.88,5.87,3.00)
,(16,'B',28.50,44.00,6.75,5.15)
,(17,'D',28.50,27.88,5.87,3.00)
,(18,'E',29.18,34.71,8.04,5.58)
,(19,'D',33.50,27.88,5.87,2.99)
,(20,'B',34.50,44.00,6.75,5.15)
,(21,'E',35.19,34.71,8.04,5.58)
,(22,'D',37.50,27.88,5.87,2.99)
,(23,'B',40.42,46.07,4.68,3.11)
,(24,'E',41.33,32.76,5.99,3.35)
,(25,'D',41.50,25.90,5.85,2.98)
,(26,'J',41.56,40.29,4.46,2.85)
,(27,'B',43.42,46.07,4.68,3.11)
,(28,'E',45.33,32.76,5.99,3.35)
,(29,'B',45.42,40.07,4.68,3.11)
,(30,'D',45.50,25.83,5.75,3.00)
,(31,'B',47.42,46.07,4.68,3.11)
,(32,'B',49.42,40.07,4.68,3.11)
,(33,'E',49.45,32.75,6.00,3.14)
,(34,'D',49.50,25.83,5.75,3.00)
,(35,'F',50.56,46.05,4.46,2.83)
,(36,'B',53.44,32.25,6.50,3.13)
,(37,'D',53.50,25.83,5.75,3.00)
,(38,'J',53.56,40.29,4.46,2.85)
,(39,'F',54.56,46.05,4.46,2.83)
,(40,'B',57.44,32.25,6.50,3.13)
,(41,'D',57.50,25.83,5.75,3.00)
,(42,'J',57.56,40.29,4.46,2.85)
,(43,'F',58.57,46.29,4.46,2.83)
,(44,'E',60.97,26.85,4.90,2.06)
,(45,'B',61.42,40.07,4.68,3.11)
,(46,'E',61.47,33.13,4.62,3.05)
,(47,'F',61.57,46.29,4.46,2.83)
,(48,'E',63.97,26.85,4.90,2.06)
,(49,'F',64.56,46.29,4.46,2.83)
,(50,'B',65.42,40.07,4.68,3.11)
,(51,'E',65.47,33.13,4.62,3.05)
,(52,'D',67.50,27.07,4.68,2.99)
,(53,'F',68.56,46.29,4.46,2.83)
,(54,'E',69.44,32.75,6.00,3.14)
,(55,'E',69.50,40.13,4.62,3.05)
,(56,'D',71.50,27.07,4.68,2.99)
,(57,'F',72.66,46.29,4.46,2.83)
,(58,'E',73.50,40.13,4.62,3.05)
,(59,'E',74.47,33.13,4.62,3.05)
,(60,'C',75.15,26.07,5.68,3.91)
,(61,'F',75.66,46.29,4.46,2.83)
,(62,'E',77.62,38.24,4.51,2.73)
,(63,'E',78.47,33.13,4.62,3.05)
,(64,'F',79.57,43.02,8.73,2.88)
,(65,'C',80.15,26.07,5.68,3.91)
,(66,'E',80.62,38.24,4.51,2.73)
,(67,'F',83.15,43.01,8.74,1.93)
,(68,'E',83.47,33.13,4.62,3.05)
,(69,'E',83.92,38.06,4.69,2.18)
,(70,'C',84.26,26.78,4.97,3.47)
,(71,'C',85.90,43.86,7.89,2.18)
,(72,'G',87.25,35.23,6.52,3.54)
,(73,'H',88.00,26.00,6.50,4.00)
,(74,'C',88.90,43.86,7.89,2.18)
,(75,'B',91.05,35.23,6.52,4.18)
,(76,'C',91.06,42.92,8.83,1.92)
,(77,'I',92.19,26.70,5.06,3.65)
,(78,'C',93.06,42.92,8.83,1.92)
;

Когда я визуализирую эти элементы, я получаю что-то вроде (где каждый цвет имеет разные атрибуты A, B, C и т. Д.):

visualisation of rectangles in 2d

Чего я хочу добиться - это выбрать только те строки, которые создают группы с одинаковым атрибутом.Или, другими словами, в конце я хочу узнать количество одинаковых прямоугольников в непосредственном соседе каждого из прямоугольников.

Мне нужно реализовать решение в SQL / T-SQL.

Может быть, кто-то уже сталкивался с такой проблемой и мог бы предложить какое-то решение.

Большое спасибо за любые предложения,

Ответы [ 2 ]

0 голосов
/ 24 сентября 2018

Выберите объекты, которые создают группы с одинаковым атрибутом, а также один объект на основе высоты и веса прямоугольника.

Запрос

select *, count(id) over (partition by attr, height, width) same_rectangles from example_rect
0 голосов
/ 23 сентября 2018

Есть несколько важных деталей, которые могут оказать существенное влияние на этот ответ.Некоторые из них уже были заданы в комментариях.

  1. Что определяет прямой сосед?На данный момент я предполагаю, что вы просто хотите соседей по горизонтальной оси.

  2. Учитывая, что есть прямоугольники разной высоты и вертикального выравнивания, нам, вероятно, понадобятся некоторые предположения о том, кто является соседом.Я определю соседа как ближайший прямоугольник справа с некоторой частью прямоугольника между горизонтальными линиями, нарисованными сверху и снизу базового прямоугольника.Это означает, что могут быть связи.

  3. Каков масштаб набора данных?На данный момент я предполагаю, что это относительно мало.Если набор данных очень большой, я бы рекомендовал использовать встроенный тип данных геометрии и использовать пространственный индекс .

  4. Что делатьВы хотите, чтобы в выводе были все прямоугольники в группе или только первый?

Пожалуйста, уточните все детали, и я постараюсь обновить.

Предполагая небольшой набор данных,горизонтальные совпадения и повторение каждого «совпадения» в виде одной строки с «левым» и «правым» прямоугольниками.Обратите внимание, что если есть группа из трех прямоугольников, это вернет две строки 1-> 2 и 2-> 3.Этот шаблон будет продолжен для группы из N смежных прямоугольников с одним и тем же типом атрибута.

Учитывая эти предположения, проблему можно разделить на несколько этапов.Во-первых, учитывая прямоугольник (скажем, rect_0), идентифицируйте всех соседей (соседей) справа (я собираюсь работать слева направо).Во-вторых, определить наиболее близкие из них.Третья проверка на соответствие атрибутов.

-- part 1 find all potential neighbors
with part_1 as (
    select
        a.id as rect_a_id
      , b.id as rect_b_id
      , a.attr as rect_a_attr
      , b.attr as rect_b_attr
      , (b.x-a.x) as dist_right
    from
        dbo.example_rect as a
        inner join dbo.example_rect as b
            on
            a.id<>b.id -- dont compare against self
            and a.x<b.x -- only check things to the 'right' of rect a
            and (a.y+a.height) >b.y -- the top of rect a should be > the bottom of rect b
            and a.y< (b.y+b.height) -- the bottom of rect a should be < the top of rect b
                                    -- if the top of a is greater than the bottom of b AND
                                    -- the bottom of a is less than the top of b then there
                                    -- has to be some overlap
)
-- part 2 find the 'closest' neighbors, note there can be ties
, part_2 as (
    select
        a.rect_a_id
      , a.rect_b_id
      , a.rect_a_attr
      , a.rect_b_attr
      , a.dist_right
    from
        part_1 as a
        inner join (select part_1.rect_a_id, min(part_1.dist_right) as min_dist_right from part_1 group by part_1.rect_a_id) as b
            on
            a.rect_a_id=b.rect_a_id
            and a.dist_right=b.min_dist_right
)
-- part 3 return the 'closest' neighobrs that have the same attribute types, note
-- this could easily be moved up into part 2 but was separated for simplicity
select part_2.rect_a_id, part_2.rect_b_id from part_2 where part_2.rect_a_attr=part_2.rect_b_attr;
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...