Custom SQL
The Custom SQL tool allows you to write custom SQL queries for data analysis directly within your workflows. This powerful feature enables advanced data processing that goes beyond GOAT's built-in tools.
This is an advanced feature intended for users with SQL knowledge. Incorrect queries may cause workflows to fail or produce unexpected results. If you need help writing SQL queries, you can use AI assistants to help generate and explain the code.
Overviewβ
The Custom SQL tool connects to GOAT's DuckDB backend, giving you direct access to query your datasets using SQL syntax. You can:
- Execute complex analytical queries
- Join multiple datasets
- Perform aggregations and statistical calculations
- Create derived datasets with custom logic
- Access advanced spatial functions
Using Custom SQLβ
Adding the Toolβ
Writing SQL Queriesβ
In the SQL Query section of the configuration panel, click Write SQL Query (or Edit SQL Query once a query exists) to open the Custom SQL Editor, and write your query in the editor at the top:
SELECT
h.*,
p.population_density
FROM input_1 h
JOIN input_2 p ON ST_Intersects(h.geometry, p.geometry)
WHERE p.population_density > 1000
The editor capitalizes SQL keywords and suggests table and column names as you type; press Tab to accept a suggestion. On the Build tab below the editor, pick Tables, Operators or a function category on the left and click an entry in the middle list to insert it at the cursor; clicking a column inserts it with its table name, for example input_1.height. The Help panel on the right describes the entry under your mouse pointer.
When the query is ready, click Apply to save it to the node. The query is then shown in the SQL Query section; click it to open the editor again.
Input Referencesβ
- input_1, input_2, input_3: Reference your connected datasets using these table names
- The number corresponds to the connection order on the node
- You can connect up to 3 input datasets per Custom SQL node
Additional Layersβ
Besides the connected inputs, you can query up to two more layers without connecting them on the canvas. Under Additional Layers, click Add layer and choose From Project or My datasets. Each added layer is referenced by its Table Alias (extra_1 and extra_2 by default), which you can change; aliases may contain only letters, numbers and underscores.
Geometry and Unitsβ
Every layer has its geometry in a column named geometry, in WGS 84 longitude and latitude (EPSG:4326). Spatial functions therefore measure in degrees: ST_Distance(a.geometry, b.geometry) returns degrees, not metres. For metres and square metres, first transform the geometry into a projected coordinate system, for example UTM zone 32N, which covers most of Germany:
ST_Transform(geometry, 'EPSG:4326', 'EPSG:25832', always_xy := true)
For other regions, use the UTM zone of the area. Return the original geometry column, or transform the result back to EPSG:4326, so the result shows in the right place on the map.
Available Functionsβ
The Custom SQL tool supports standard SQL functions plus spatial operations:
Spatial Functions:
ST_Intersects()- Check if geometries intersectST_Within()- Test if geometry is within anotherST_DWithin()- Test if geometries are within a distance of each otherST_Distance()- Calculate distances between geometriesST_Buffer()- Create buffers around geometriesST_Area()- Calculate geometry areaST_Length()- Calculate line lengthST_Transform()- Transform geometries to another coordinate system
Distances, areas, lengths and buffer sizes are in the units of the coordinate system; see Geometry and Units.
Analytical Functions:
AVG(),SUM(),COUNT()- Statistical aggregationsPERCENTILE_CONT()- Calculate percentilesROW_NUMBER(),RANK()- Window functionsCASE WHEN- Conditional logic
Query Validationβ
Examplesβ
Basic Filtering and Selectionβ
-- Residential buildings taller than 10 m
SELECT building_type, height, geometry
FROM input_1
WHERE building_type = 'residential'
AND height > 10
Spatial Join Analysisβ
-- Amenities within 500 m of a transit stop, with the distance in metres
WITH a AS (
SELECT name, amenity_type, geometry,
ST_Transform(geometry, 'EPSG:4326', 'EPSG:25832', always_xy := true) AS geom_m
FROM input_1
), t AS (
SELECT stop_name,
ST_Transform(geometry, 'EPSG:4326', 'EPSG:25832', always_xy := true) AS geom_m
FROM input_2
)
SELECT
a.name AS amenity_name,
a.amenity_type,
t.stop_name,
ST_Distance(a.geom_m, t.geom_m) AS distance_m,
a.geometry
FROM a
JOIN t ON ST_DWithin(a.geom_m, t.geom_m, 500)
ORDER BY distance_m
Aggregation by Areaβ
-- Number of points in each district, including districts without points
SELECT
admin.district_name,
COUNT(points.geometry) AS point_count,
ANY_VALUE(admin.geometry) AS geometry
FROM input_2 admin
LEFT JOIN input_1 points ON ST_Within(points.geometry, admin.geometry)
GROUP BY admin.district_name
Best Practicesβ
- Join tables on spatial predicates such as
ST_Intersects()orST_Within()rather than comparing every pair of rows yourself - Limit results during development with
LIMIT 100 - Test with small datasets first, then scale up
- Ensure geometry columns are properly formatted for spatial operations
- Cast data types explicitly when joining different datasets
- Check for NULL values in critical columns
Query Optimizationβ
Use Spatial Predicates: Join on spatial predicates such as ST_Intersects(), ST_Within() or ST_DWithin(), so the database can match nearby geometries efficiently.
Column Selection: Select only the columns you need rather than using SELECT *.
Proper Joins: Use appropriate join types (INNER, LEFT, RIGHT) based on your analysis needs.
Error Handlingβ
Common issues and solutions:
- Unknown table: Ensure input datasets are properly connected and that the query uses their table names (
input_1toinput_3, or the Table Alias of an additional layer) - Unknown column: Check column names in your input datasets; the Tables list on the Build tab shows the columns of each table
- Geometry error: Verify geometry columns are valid and properly formatted
- Only SELECT statements are allowed: Write a single
SELECTquery (optionally starting withWITH); statements that change data, such asCREATE,INSERT,UPDATEorDELETE, are rejected - Long-running query: Break complex queries into smaller steps
Output and Integrationβ
The Custom SQL tool creates a new temporary layer containing your query results, named after the Result Layer Name field in the Output section (default: Custom SQL). After a successful run, the configuration panel shows the Dataset details of the result and these Actions:
- Table: Show the result in the data view below the canvas
- Map: Show the result on a map (only for results with a geometry column)
- Save dataset: Save the result as a permanent dataset
You can also:
- Connect the output to other workflow tools for further analysis
- Add a Save as dataset node to save the results as a permanent dataset each time the workflow runs
Custom SQL queries support workflow variables using the {{@variable_name}} syntax for parameterized queries. Type {{@ in the editor to get a list of the workflow's variables.
Limitationsβ
- Maximum of 3 connected inputs and 2 additional layers per Custom SQL node
- Only a single
SELECTstatement is allowed - Results without a geometry column are created as a table and cannot be shown on the map
- Some advanced DuckDB functions may not be available
For more complex analysis requirements, consider using multiple Custom SQL nodes or combining with other workflow tools.