I'm trying to divide the map of an area into 1 km x 1 km square grids and ultimately, count and retrieve how many points (given their latitude and longitude values) fall into each square grid of this map. Can this operation be done in the PostGIS, if so, how can I do that?
UPDATE: Mike Toews has a detailed answer here:
https://gis.stackexchange.com/questions/16374/how-to-create-a-regular-polygon-grid-in-postgis
As mentioned in my comment
make a regular grid. To make a 1 km grid for a whole country, this could be challenging, since the earth is not flat and cannot be divided into perfect 1 km grids.
To make a 1 km grid, you need a projected coordinate system, with length units of metres. WGS84 (EPSG:4326) cannot do this, since it has units of degrees lat/long. To find a suitable projection system, you need to find an "equal area" projection, such as Lambert azimuthal equal-area projection (LAEA). For example all of Europe could use ETRS-LAEA (EPSG:3035), although there might be some distortion in some parts. Or if in New Zealand, New Zealand Transverse Mercator 2000. Each region generally has a good projection to use.
To run your PostGIS query, you would need to project geometries onto the grid using ST_Transform(geom, 3035)
(e.g., for ETRS-LAEA).
I wrote a PostGIS function to generate hex grids on top of another layer.
DO $$
DECLARE
_curs CURSOR FOR SELECT geom3857 FROM nrw;
_table TEXT := 'nrw_hx_10k';
_srid INTEGER := 3857;
_height NUMERIC := 10000;
_width NUMERIC := _height * 0.866;
_geom GEOMETRY;
_hx TEXT := 'POLYGON((' || 0 || ' ' || 0 || ',' || (_width * 0.5) || ' ' || (_height * 0.25) || ',' ||
(_width * 0.5) || ' '
|| (_height * 0.75) || ',' || 0 || ' ' || _height || ',' || (-1 * (_width * 0.5)) || ' ' ||
(_height * 0.75) || ',' ||
(-1 * (_width * 0.5)) || ' ' || (_height * 0.25) || ',' || 0 || ' ' || 0 || '))';
_hx_g GEOMETRY := ST_SetSRID(_hx::GEOMETRY, _srid);
BEGIN
CREATE TEMP TABLE hx_tmp (geom GEOMETRY(POLYGON));
OPEN _curs;
LOOP
FETCH
_curs INTO _geom;
EXIT WHEN NOT FOUND;
INSERT INTO hx_tmp
SELECT
ST_Translate(_hx_g, x_series, y_series)::GEOMETRY(POLYGON) geom
FROM
generate_series(
(st_xmin(_geom) / _width)::INTEGER * _width - _width,
(st_xmax(_geom) / _width)::INTEGER * _width + _width,
_width) x_series,
generate_series(
(st_ymin(_geom) / (_height * 1.5))::INTEGER * (_height * 1.5) - _height,
(st_ymax(_geom) / (_height * 1.5))::INTEGER * (_height * 1.5) + _height,
_height * 1.5) y_series
WHERE
ST_Intersects(ST_Translate(_hx_g, x_series, y_series)::GEOMETRY(POLYGON), _geom);
INSERT INTO hx_tmp
SELECT ST_Translate(_hx_g, x_series, y_series)::GEOMETRY(POLYGON) geom
FROM
generate_series(
(st_xmin(_geom) / _width)::INTEGER * _width - (_width * 1.5),
(st_xmax(_geom) / _width)::INTEGER * _width + _width,
_width) x_series,
generate_series(
(st_ymin(_geom) / (_height * 1.5))::INTEGER * (_height * 1.5) - (_height * 1.75),
(st_ymax(_geom) / (_height * 1.5))::INTEGER * (_height * 1.5) + _height,
_height * 1.5) y_series
WHERE
ST_Intersects(ST_Translate(_hx_g, x_series, y_series)::GEOMETRY(POLYGON), _geom);
END LOOP;
CLOSE _curs;
CREATE INDEX sidx_hx_tmp_geom ON hx_tmp USING GIST (geom);
EXECUTE 'DROP TABLE IF EXISTS '|| _table;
EXECUTE 'CREATE TABLE '|| _table ||' (geom GEOMETRY(POLYGON, '|| _srid ||'))';
EXECUTE 'INSERT INTO '|| _table ||' SELECT * FROM hx_tmp GROUP BY geom';
EXECUTE 'CREATE INDEX sidx_'|| _table ||'_geom ON '|| _table ||' USING GIST (geom)';
DROP TABLE IF EXISTS hx_tmp;
END $$;
Input parameters must be set for:
_curs: The geometry field name and the table name of input geometries.
_table: The name of the output table.
_srid: The geographic projection code of the input (and output) geometries.
_height: The height of a hexgon grid cell in projection units.
I generate a scaled hexagon geometry in the declare block and then loop through the input geometries. In the loop, I generate series for the x and y extent plus some for each input geometry. The hexagon is translated and inserted into a temporary table if the two geometries intersect. A second pair of series is generated alternative offset rows.
Finally I group the hexagon grid cells by their geometries to remove duplicates.
There is a more detailed description and some background on medium.