Примеры использования виртуальных слоёв
Ниже приведены некоторые типичные задачи, возникающие при работе с картографическими данными, а также примеры их решения при помощи виртуальных слоёв.
Виртуальный слой основан на Представлении (View) - сущности базы данных, которая сама по себе не содержит никаких данных. Её содержимое выбирается из других слоёв с помощью выполнения SQL-запроса. Этот механизм предоставляет широкие возможности по видоизменению исходных данных (например, объединение слоёв, фильтрация, группировка, агрегация, сортировка и т.д.) без их фактической модификации. При помощи функций расширения PostGIS в виртуальных слоях можно осуществлять различные операции с геометрией.
Подробнее о языке SQL и особенностях СУБД PostgreSQL можно узнать в документации. Информация о расширении PostGIS: официальный сайт PostGIS (на английском), сайт GIS-Lab (на русском).
Общая информация
Виртуальные слои подразумевают использование SQL-запросов только с операциями выборки данных.
В результате запроса должен присутствовать уникальный идентификатор объекта (колонка orbis_id
). В случае необходимости, orbis_id
может быть сгенерирован конструкцией (row_number() OVER ())::int AS orbis_id
, которая номерует каждую запись в виртуальном слое по порядку.
Опционально в виртуальном слое может присутствовать колонка geom
, содержащая пространственные данные объектов в «проекции Меркатора» - EPSG:3857.
Примеры задач по работе с данными
1. Сделать копию слоя без фактического дублирования
Может использоваться, например, для другого отображения тех же данных. Изменения данных исходного слоя автоматически отразятся в виртуальном.
SELECT *
FROM layer1;
2. Сделать виртуальную копию слоя с меньшим количеством записей
Используется для ограничения количества записей в виртуальном слое.
SELECT *
FROM layer1
LIMIT 10;
3. Сделать виртуальную копию слоя с меньшим количеством полей
Используется для конкретного указания списка полей в виртуальном слое.
SELECT
orbis_id,
geom,
value AS "name"
FROM layer1;
Конструкция value AS "name"
означает, что колонка value
в виртуальном слое получит код name
.
Подробнее...
4. Сделать виртуальную копию слоя с новым вычисляемым значением
Используется если в исходных данных нет нужного значения, но его можно вычислить.
SELECT
*, (value1 + value2) / 1000 AS "value3"
FROM layer1;
(value1 + value2) / 1000
- вычисляемое значение из колонок слоя, а value3
- код новой вычисляемой колонки. Для получения результата могут использоваться различные функции и операторы, например математические, строковые, приведения типов и многие другие.
5. Сделать виртуальную копию слоя с объектами, удовлетворяющими условию
Используется для фильтрации объектов по одному или нескольким условиям - например, когда нужно разделить объекты по типам на отдельные слои для возможности раздельного управления отображением. Любая запись, не удовлетворяющая условиям, исключается из результата.
SELECT *
FROM layer1
WHERE name = 'Москва' AND value > 1000;
name = 'Москва' AND value > 1000;
- условие фильтрации. Оно может быть задано при помощи функций и операторов сравнения, логических операторов, операторов поиска по шаблону и многих других.
6. Соединить данные двух слоев
Используется при необходимости одновременного обращения к данным нескольких слоёв или даже для повторного обращения к данным одного слоя.
SELECT
(row_number() OVER ())::int AS orbis_id, l1.geom,
l2.value,
l1.value * l2.value as result
FROM layer1 as l1
INNER JOIN layer2 as l2
ON l1.orbis_id = l2.layer1_id;
Существует несколько типов соединений, в данном примере для соединения layer1
c layer2
используется INNER JOIN
- каждому объекту в layer1
будут сопоставлены объекты из layer2
, удовлетворяющие условию ON l1.orbis_id = l2.layer1_id
, лишние записи будут откинуты.
Для обеспечения уникальности идентификатора объекта (orbis_id
) используется конструкция (row_number() OVER ())::int AS orbis_id
, которая номерует каждую запись в виртуальном слое по порядку.
7. Сгруппировать данные слоя
Используется при необходимости вычислить агрегированные значения по слою - например, количество объектов определённого типа, их сумму, среднее и т.д.
SELECT
(row_number() OVER ())::int AS orbis_id,
null::geometry AS "geom",
count(*),
SUM(column1) AS "area",
column2 AS "name"
FROM
layer1
GROUP BY
column2;
В блоке GROUP BY
определяется набор колонок, которые будут использоваться для разделения объектов на категории. Каждому уникальному набору значений этих колонок будет соответствовать новая категория. Эти колонки могут быть вынесены в блок SELECT
в исходном виде без агрегатных функций. В данном примере такая колонка одна - column2
.
Подробнее...
Вместе с группировкой обычно используются агрегатные функции, в данном примере это функция SUM()
, находящая сумму значений колонки сolumn1
в каждой категории.
Если необходимо объединить весь слой в один объект, необходимо использовать агрегатную функцию без конструкции GROUP BY
Примеры задач по работе с геометрией при помощи расширения PostGIS
1. Вычислить площадь объектов слоя
SELECT *,
ST_Area(ST_Transform(geom, 4326)::geography) AS "area"
FROM layer
Функция ST_Area()
принимает на вход геометрию, которая соответствует типу Polygon
или MultiPolygon
.
Для получения площади в квадратных метрах используется конструкция ST_Area(ST_Transform(geom, 4326)::geography)
, в которой геометрия предварительно переводится в метрическую систему координат.
Подробнее...
2. Вычислить длину линейных объектов
SELECT *,
ST_Length((ST_Transform(geom, 4326)::geography)) AS "length"
FROM
layer
ST_Length()
принимает на вход геометрию, которая соответствует типу Line
или MultiLine
.
Для получения длины в метрах используется конструкций ST_Length((ST_Transform(geom, 4326)::geography))
, в которой геометрия предварительно переводится в метрическую систему координат.
Подробнее...
3. Вычисление центра объектов
SELECT
(row_number() OVER ())::int AS orbis_id,
ST_Centroid(geom) AS geom
FROM
layer
ST_Centroid()
вычисляет точку геометрического центра геометрии.
Подробнее...
4. Вычисление расстояния между объектами
SELECT
(row_number() OVER ())::int AS orbis_id,
l1.geom,
ST_Distance(l1.geom, l2.geom) AS "distance"
FROM
layer1 as l1
INNER JOIN
layer2 AS l2
ON
l2.geom NOTNULL
Для каждого объекта layer1
будут созданы записи с полем, в котором содержится расстояние до каждого объекта layer2
. Количество записей в виртуальном слое зависит от условия соединения таблиц.
ST_Distance()
принимает на вход две геометрии. На выходе расстояние между геометриями.
Подробнее...
5. Создание точки из колонок широты и долготы
SELECT
orbis_id,
ST_Transform(ST_SetSRID(ST_MakePoint(longitude, latitude), 4326), 3857) AS geom
FROM
layer
Функция создания точки - ST_MakePoint(). После создания точки необходимо привязать геометрию к определенной системе координат. Функция привязки к системе координат - ST_SetSRID(). В завершении, необходимо установить правильную проекцию EPSG:3857 - ST_Transform
6. Создание линии из точек
SELECT
orbis_id,
ST_MakeLine(geom) AS geom
FROM
layer
ST_MakeLine()
является агрегатной функцией. Принимает на вход массив Point
(точек), два значения Point
или набор Point
.
Подробнее...
7. Создание полигона
SELECT
orbis_id,
ST_MakePolygon(geom) AS geom
FROM
layer
ST_MakePolygon()
является агрегатной функцией. Принимает на вход Line
или набор данных, состоящий из внешнего и внутреннего значения Line
.
Подробнее...
8. Создание окружности вокруг точки
SELECT
orbis_id,
ST_Transform(ST_Buffer((ST_Transform(geom, 4326)::geography), radius)::geometry, 3857) AS geom
FROM
layer
ST_Buffer()
принимает на вход центр окружности(geom
), ее радиус (radius
) и ряд дополнительных параметров.
Для возможности задания радиуса окружности в метрах используется конструкция ST_Transform(ST_Buffer((ST_Transform(geom, 4326)::geography), radius)::geometry, 3857)
, которая переводит геометрию в метрическую систему координат, строит окружность в метрах и возвращает в исходную проекцию.
Подробнее...
9. Получение объектов, полностью находящихся внутри других объектов
SELECT
l1.*
FROM
layer1 AS l1
INNER JOIN
layer2 AS l2
ON
l2.orbis_id = 1
WHERE
ST_Contains(l2.geom, l1.geom);
Мы объединяем два слоя, при этом в слое layer2
(l2
) находится полигон, по которому производится проверка - содержится ли геометрия объектов внутри данного полигона или нет. В данном примере считаем, что полигон проверки имеет значение orbis_id
равное 1
. Для проверки можно использовать сразу несколько полигонов, в этом случае при объединении таблиц необходимо указать поля которые нам необходимы. Например, для извлечения всех полигонов проверки необходимо поставить условие ON l2.orbis_id NOTNULL
.
Для получения объектов, которые не находятся в области, необходимо поставить отрицательное условие по функции ST_Contains()
. Пример: WHERE NOT ST_Contains(l2.geom, l1.geom);
ST_Contains()
принимает на вход два значения или массива геометрии. На выходе boolean
значение (true
, false
).
Подробнее...
10. Получение объектов, пересекающих другие объекты
SELECT
l1.*
FROM
layer1 AS l1
INNER JOIN
layer2 AS l2
ON
l2.orbis_id = 1
WHERE
ST_Intersects(l2.geom, l1.geom);
Объединение слоев описано в пункте 9.
Для получения объектов, которые не пересекают область, необходимо поставить отрицательное условие по функции ST_Intersects()
. Пример: WHERE NOT ST_Intersects(l2.geom, l1.geom);
ST_Intersects()
принимает на вход два значения или массива геометрии. На выходе boolean
значение (true
, false
).
Подробнее...
11. Получение объектов, соприкасающихся c другими объектами
Используется для получения объектов, чья геометрия соприкасается с геометрией других объектов, но при этом они не пересекаются.
SELECT
l1.*
FROM
layer1 AS l1
INNER JOIN
layer2 AS l2
ON
l2.orbis_id = 1
WHERE
ST_Touches(l2.geom, l1.geom);
Объединение слоев описано в пункте 9.
Для получения объектов, которые не пересекают область, необходимо поставить отрицательное условие по функции ST_Touches()
. Пример: WHERE NOT ST_Touches(l2.geom, l1.geom);
ST_Touches()
принимает на вход два значения или массива геометрии. На выходе boolean
значение (true
, false
).
Подробнее...
12. Получение объектов, находящихся на определенном расстоянии от других объектов
SELECT
l1.*
FROM
layer1 AS l1
INNER JOIN
layer2 AS l2
ON
l2.orbis_id = 1
WHERE
ST_DWithin(ST_Transform(l1.geom, 4326)::geography, ST_Transform(l2.geom, 4326)::geography, 100);
Объединение слоев описано в пункте 9.
Для получения объектов, которые находятся на расстоянии больше указанного, необходимо поставить отрицательное условие по функции ST_DWithin()
. Пример: WHERE NOT ST_DWithin(.geom, l2.geom, 10000);
ST_DWithin()
принимает на вход два значения или массива геометрии и расстояние. На выходе boolean
значение (true
, false
).
Для возможности указания расстояния в метрах используется конструкция ST_Transform(l1.geom, 4326)::geography
, которая переводит геометрию в метрическую систему координат.
Подробнее...
13. Получение объектов с одинаковой геометрией
SELECT
l1.*
FROM
layer1 AS l1
INNER JOIN
layer2 AS l2
ON
l2.orbis_id = 1
WHERE
ST_Equals(l1.geom, l2.geom);
Объединение слоев описано в пункте 9.
Для получения объектов, которые не находятся в области, необходимо поставить отрицательное условие по функции ST_Equals()
. Пример: WHERE NOT ST_Equals(l1.geom, l2.geom);
ST_Equals()
принимает на вход два значения или массива геометрии. На выходе boolean
значение (true
, false
).
Подробнее...
14. Объединение геометрии объектов
SELECT
(row_number() OVER ())::int AS orbis_id,
ST_UNION(geom) AS geom,
column
FROM
layer
GROUP BY
column
ST_UNION()
является агрегатной функцией, в данном примере осуществляется группировка по колонке column
. Принимает на вход набор или массив геометрии одно типа (Point
, Polygon
, Line
). На выходе создает Multi*
геометрию соответствующего типа.
Подробнее...
15. Исключить геометрию одного объекта из геометрии другого
Используется для получения обрезанной геометрии объектов.
SELECT
(row_number() OVER ())::int AS orbis_id,
ST_Difference(l1.geom, l2.geom) AS "geom"
FROM
layer1 AS l1
INNER JOIN
layer2 AS l2
ON
l2.orbis_id = 1
Объединение слоев описано в пункте 9.
ST_Difference()
принимает на вход исходную геометрию, и геометрию, по которой мы будем её обрезать.
Подробнее...
16. Получить геометрию пересечения двух объектов
SELECT
(row_number() OVER ())::int AS orbis_id,
ST_Intersection(l1.geom, l2.geom) AS "geom"
FROM
layer1 AS l1
INNER JOIN
layer2 AS l2
ON
l2.orbis_id = 1
Объединение слоев описано в пункте 9.
ST_Intersection()
принимает на вход две геометрии объектов, возвращает геометрию для их пересечения.
Подробнее...