I use QGIS 3.8.0 and I'm looking for tools to assign a polygon parent depending on the value. I attach the picture, where there are several polygons with different names.

I would like to get the name of the parent (polygon with neighboring value and containing this polygon) in the attribute table.

polygons aggregation

I've tried to use aggregate function but my skills are to weak.

I've used this command:

 filter:= contains( $geometry, geometry(@parent) ) 

It should look like this:

attribute table

Anyone have any idea how can I get this information ?

  • 1
    Do the polygons overlap ? Commented Jul 29, 2019 at 13:36
  • Yes. This is the problem
    – Michal De
    Commented Jul 30, 2019 at 9:17
  • 1
    Overlapping polygons should be a good news in this case isn't it ? Commented Jul 30, 2019 at 9:45

1 Answer 1


As I understand your issue,

Another way of stating your problem is : "for each polygon i look for the smallest one that contains him".

Edit : As said by J. Monticolo, this will work only if your polygon overlaps. Otherwise, you still can work with the St_ExteriorRing of your polygons (must be polygons not MultiGeometry) and apply the same traitment, not tested but should work.

Maybe there is some QGIS plug-in to do it simply, I don't know. But I will give you a solution with Postgres/postgis, if you want to use it, you have to install postgres and then upload your shapefile in postgres. And then use some Sql queries ...

If you go this way, you can make a query where you look if polygons are contained in other polygons. then you have couples of polygon, you just need to partition them in group and select the smallest one. So you can use Partition , ordering by area and partitioning by name, and you find what you want.

Exemple :


WITH contains AS (
  SELECT t2.name AS container,
         t1.name AS contained,
         ST_AREA(t2.geom) AS area
  FROM work.test_poly AS t2,
       work.test_poly AS t1
  WHERE ST_CONTAINS(t2.geom, t1.geom) 
  ORDER BY ST_AREA(t2.geom)

pair_polygons AS (
  SELECT contains.container,
         area AS area, 
         row_number() OVER(
           PARTITION BY contained 
           ORDER BY area) AS cluster
  FROM contains 
  WHERE container != contained

master_slave AS (
  SELECT container,
  FROM pair_polygons
  WHERE cluster = 1

UPDATE work.test_poly
SET master = container
FROM master_slave
WHERE name = contained

poly_test is the name of my blank table and i use couple of CTE here but you should be able to adapt =)

this will give you this :


I think there is also other ways to do it ...

  • 1
    It works only if the polygons overlap, hence my question to the author. Otherwise, nice solution. Commented Jul 30, 2019 at 8:36
  • Indeed, this will only work with full polygon, i added some information about the St_ExteriorRing which should solve the issue if polygons doesn't overlap postgis.net/docs/ST_ExteriorRing.html Commented Jul 30, 2019 at 8:47

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.