Union in GIS: choosing between overlay, merge, unary union, and dissolve

Understanding the different types of unions in GIS

Spatial union is one of the fundamental operations in geomatics. It allows you to combine multiple layers or entities to produce new geometries or enrich attributes. However, behind this seemingly simple term lie several variations depending on the tool or library used.

In this article, we will detail:

  • the main types of union (ST_Union, Union, ArcGIS spatial union, etc.)
  • their conceptual and practical differences
  • examples of implementation in SQL (PostGIS) and Python (QGIS/Processing).



Why is it often confusing?

The word union covers several different operations depending on the tool used:

  • Union (overlay) as in QGIS/ArcGIS: cutting + concatenation of attributes.
  • ST_Union (PostGIS): geometric merge (global or group dissolve).
  • ST_UnaryUnion (PostGIS): fast/robust topological merge (topology-preserving).
  • Dissolve by attribute: aggregate entities that share the same value.

Choosing the right operation avoids surprises… and XXL SQL.


1) Union (overlay) – the “true” Union in QGIS/ArcGIS style

What it does

  • Keeps all geometric pieces resulting from overlaps and non-overlaps.
  • Concatenates the attributes of the two layers (with NULL on the missing side).
  • Ideal for multi-criteria analyses (partially overlapping zones).

Key points to remember

This is an overlay operation, not a geometry merge.

The result may contain many objects (each intersection creates pieces).

Python example (QGIS Processing)Processing)

import processing
from qgis.core import QgsProject

# Deux couches chargées dans QGIS (QgsVectorLayer) : layer_a, layer_b
result = processing.run("qgis:union", {
    "INPUT": layer_a,
    "OVERLAY": layer_b,
    "OUTPUT": "memory:"  # ou un GPKG/PG
})

union_layer = result["OUTPUT"]
QgsProject.instance().addMapLayer(union_layer)

PostGIS example (SQL pattern “overlay union”)

Compact version without attributes (just the ID of the pairs + geom).

WITH pairs AS (
  SELECT a.gid AS ida, b.gid AS idb, ST_Intersection(a.geom, b.geom) AS geom
  FROM plugin.communes a
  JOIN plugin.logements b ON ST_Intersects(a.geom, b.geom)
  WHERE NOT ST_IsEmpty(ST_Intersection(a.geom, b.geom))
),
inter_union AS (
  SELECT ST_UnaryUnion(geom) AS geom FROM pairs
),
a_only AS (
  SELECT a.gid AS ida, NULL::integer AS idb,
         ST_Difference(a.geom, (SELECT geom FROM inter_union)) AS geom
  FROM plugin.communes a
  WHERE NOT ST_IsEmpty(ST_Difference(a.geom, (SELECT geom FROM inter_union)))
),
b_only AS (
  SELECT NULL::integer AS ida, b.gid AS idb,
         ST_Difference(b.geom, (SELECT geom FROM inter_union)) AS geom
  FROM plugin.logements b
  WHERE NOT ST_IsEmpty(ST_Difference(b.geom, (SELECT geom FROM inter_union)))
)
SELECT * FROM pairs
UNION ALL
SELECT * FROM a_only
UNION ALL
SELECT * FROM b_only;


2) ST_Union – geometric merge (global dissolve)

What it does

  • Merges a set of geometries into a single one (Multi*) without retaining the attributes.
  • By default, manages topology, but ST_UnaryUnion is generally more robust/faster.

When to use it

  • To dissolve adjoining polygons (e.g., create the overall footprint).
  • To pre-aggregate before a buffer or area calculation.

SQL example: merge two tables into a single geometryrie

CREATE TABLE plugin.emprise_globale AS
SELECT ST_UnaryUnion(geom) AS geom
FROM (
  SELECT geom FROM plugin.communes
  UNION ALL
  SELECT geom FROM plugin.logements
) s;

Python example (psycopg2)

import psycopg2
conn = psycopg2.connect("dbname=... user=... password=... host=... port=...")
cur = conn.cursor()
cur.execute("""
  DROP TABLE IF EXISTS plugin.emprise_globale;
  CREATE TABLE plugin.emprise_globale AS
  SELECT ST_UnaryUnion(geom) AS geom
  FROM (
    SELECT geom FROM plugin.communes
    UNION ALL
    SELECT geom FROM plugin.logements
  ) s;
""")
conn.commit()
cur.close()
conn.close()


3) ST_UnaryUnion – topological merge (more robust)

What it does

  • Same as ST_Union, but topology-preserving and often faster.
  • Better at correcting multi-overlaps, shared rings, and small topology errors.

When to use it

  • Always for large layers or those with imperfect geometries.
  • As a building block within other queries (e.g., overlay union).

Python example (GeoPandas)

import geopandas as gpd

gdf = gpd.read_file("commun.es.gpkg")
geom_unary = gdf.unary_union  # équivalent à ST_UnaryUnion
# -> geom_unary est un (Multi)Polygon shapely


4) Dissolve by attribute (ST_Union + GROUP BY)

What it does

  • Groups entities by a key and merges the geometry within each group.
  • Attributes are not automatically aggregated (except for the key) → add your aggregates.

SQL example: dissolve municipalities

CREATE TABLE plugin.communes_par_epci AS
SELECT epci,
       ST_UnaryUnion(geom) AS geom
FROM plugin.communes
GROUP BY epci;

Python Example (QGIS Processing – Dissolve)

import processing

res = processing.run("native:dissolve", {
    "INPUT": layer_communes,
    "FIELD": ["epci"],
    "SEPARATE_DISJOINT": False,
    "OUTPUT": "memory:"
})
dissolved = res["OUTPUT"]


5) Bonus: GeoPandas – overlay(…, how=”union”)

What it does

  • Equivalent to the QGIS/ArcGIS overlay union on the scientific Python side.

import geopandas as gpd

a = gpd.read_file("plugin_communes.gpkg")
b = gpd.read_file("plugin_logements.gpkg")

u = gpd.overlay(a, b, how="union")
u.to_file("union_overlay.gpkg")


How to choose?

  • Do you want to keep the attributes of both layers + keep the non-overlapping areas?
    → Union (overlay).
  • Do you want a single merged geometry (for a footprint, a mask)?
    → ST_UnaryUnion (or ST_Union if not available).
  • Do you want to dissolve by a key (departments, EPCI, etc.)?
    → GROUP BY + ST_UnaryUnion.
  • Want to do everything in Python QGIS without SQL?
    → qgis:union (overlay) or native:dissolve (dissolve by attribute).


Comparative summary

Union type Nature Attributs Geometric result Example of use
ST_Union (PostGIS) Geometric function No (except GROUP BY) Merge polygons Dissolve municipalities in a region
UNION (QGIS/PostGIS overlay) Overlay Yes (all retained) Cut + combine Cross municipalities and housing
Union (ArcGIS) Overlay Yes (all retained) Complete partition Multi-criteria analysis


Pitfalls & best practices

  • Attributes vs. geometry: ST_Union does not merge attributes ⇒ no overlay.
  • Attribute types: in a homemade SQL overlay, align the types (or cast to text) before UNION ALL.
  • Topology: prefer ST_UnaryUnion for large or slightly “dirty” sets.
  • SRID: make sure both layers share the same SRID; if not, reproject first.
  • Polygon vs Multi: force ST_Multi(…) if you need a homogeneous type.


Summary of Python snippets (to copy and paste)

A) Overlay Union (QGIS)

import processing
from qgis.core import QgsProject

result = processing.run("qgis:union", {
    "INPUT": layer_a,
    "OVERLAY": layer_b,
    "OUTPUT": "memory:"
})
QgsProject.instance().addMapLayer(result["OUTPUT"])

B) Global merge (PostGIS)

import psycopg2
conn = psycopg2.connect("dbname=... user=... password=... host=... port=...")
cur = conn.cursor()
cur.execute("""
  DROP TABLE IF EXISTS plugin.emprise_globale;
  CREATE TABLE plugin.emprise_globale AS
  SELECT ST_UnaryUnion(geom) AS geom
  FROM (
    SELECT geom FROM plugin.communes
    UNION ALL
    SELECT geom FROM plugin.logements
  ) s;
""")
conn.commit(); cur.close(); conn.close()

C) Dissolve by attribute (QGIS)

import processing

res = processing.run("native:dissolve", {
    "INPUT": layer_communes,
    "FIELD": ["epci"],
    "OUTPUT": "memory:"
})

D) Overlay Union (GeoPandas)

import geopandas as gpd
u = gpd.overlay(gpd.read_file("a.gpkg"), gpd.read_file("b.gpkg"), how="union")
u.to_file("union_overlay.gpkg")


Conclusion

The term “union” actually covers two different concepts:

  • geometric merge (ST_Union, Dissolve) → to simplify contours.
  • overlay with attribute combination (UNION, ArcGIS Union) → for multi-criteria analysis.

The choice therefore depends on the objective: simplification or analysis.


In a future article, we will explore the performance of these different approaches in detail, as unions can quickly become computationally expensive when dealing with millions of geometries.

Si cet article vous a intéressé et que vous pensez qu'il pourrait bénéficier à d'autres personnes, n'hésitez pas à le partager sur vos réseaux sociaux en utilisant les boutons ci-dessous. Votre partage est apprécié !

Leave a Reply

Your email address will not be published. Required fields are marked *