{"id":16396368,"url":"https://github.com/clhenrick/postgresql_postgis_cheatsheet","last_synced_at":"2025-03-23T04:31:59.151Z","repository":{"id":147261472,"uuid":"82495803","full_name":"clhenrick/postgresql_postgis_cheatsheet","owner":"clhenrick","description":"Helpful tips and tricks for getting started and working with PostgreSQL and PostGIS. Please feel free to Fork \u0026 Contribute, PRs are welcome!","archived":false,"fork":false,"pushed_at":"2017-02-19T23:04:00.000Z","size":6,"stargazers_count":18,"open_issues_count":0,"forks_count":6,"subscribers_count":2,"default_branch":"master","last_synced_at":"2025-03-01T21:52:16.682Z","etag":null,"topics":["cheatsheet","how-to","howto","postgis","postgresql"],"latest_commit_sha":null,"homepage":"","language":null,"has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/clhenrick.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":null,"code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2017-02-19T22:59:23.000Z","updated_at":"2023-09-08T17:21:12.000Z","dependencies_parsed_at":null,"dependency_job_id":"041785d0-3560-41fb-96a8-3dcf3582c2a6","html_url":"https://github.com/clhenrick/postgresql_postgis_cheatsheet","commit_stats":null,"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/clhenrick%2Fpostgresql_postgis_cheatsheet","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/clhenrick%2Fpostgresql_postgis_cheatsheet/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/clhenrick%2Fpostgresql_postgis_cheatsheet/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/clhenrick%2Fpostgresql_postgis_cheatsheet/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/clhenrick","download_url":"https://codeload.github.com/clhenrick/postgresql_postgis_cheatsheet/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":244272539,"owners_count":20426753,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["cheatsheet","how-to","howto","postgis","postgresql"],"created_at":"2024-10-11T05:07:11.779Z","updated_at":"2025-03-23T04:31:59.131Z","avatar_url":"https://github.com/clhenrick.png","language":null,"funding_links":[],"categories":[],"sub_categories":[],"readme":"PostgreSQL \u0026 PostGIS Cheatsheet\n===============================\nThis is a collection of information on PostgreSQL and PostGIS for what I tend to use most often.\n\n## TOC\n- [Installing Postgres \u0026 PostGIS](#installation)  \n- [Using Postgres on the command line: PSQL](#psql)\n- [Importing Data into Postgres](#importing-data)\n- [Exporting Data from Postgres](#exporting-data)\n- [Joining Tables](#joining-tables-using-a-shared-key)\n- [Upgrading Postgres](#upgrading-postgres)\n- [PostGIS common commands](#postgis-1)\n- [Common PostGIS spatial queries](#common-spatial-queries)\n- [Spatial Indexing](#spatial-indexing)\n- [Importing spatial data into PostGIS](#importing-spatial-data-to-postgis)\n- [Exporting spatial data from PostGIS](#exporting-spatial-data-from-postgis)\n- [Other Methods of Interacting With Postgres/PostGIS](#other-methods-of-interacting-with-postgres/postgis)\n\n## Installation\n### Postgres\n- to install on Ubuntu do: `apt-get install postgresql`\n\n- to install on Mac OS X first install [homebrew](http://brew.sh/) and then do `brew install postgresql`\n\n- to install on Windows...\n\nNote that for OS X and Ubuntu you may need to run the above commands as a super user / using `sudo`.\n\n#### Set Up\nOn Ubuntu you typically need to log in as the Postgres user and do some admin things:\n\n- log in as postgres: `sudo -i -u postgres`\n- create a new user: `createuser --interactive`\n- type the name of the new user (no spaces!), typically the same name as your linux user that isn't root. You can add a new linux user by doing `adduser username`.\n- typically you want the user to have super-user privileges, so type `y` when asked.\n- create a new database that has the same name as the new user: `createdb username`\n\nFor Mac OS X you can skip the above if you install with homebrew.\n\nFor Windows....\n\n\n#### Starting the Postgres Database\nOn Mac OS X:  \n\n- to start the Postgres server do: `postgres -D /usr/local/var/postgres`\n\n- or do `pg_ctl -D /usr/local/var/postgres -l /usr/local/var/postgres/server.log start` to start and `pg_ctl -D /usr/local/var/postgres -l /usr/local/var/postgres/server.log stop` to stop\n\n- to have Postgres start everytime you boot your Mac do: `ln -sfv /usr/local/opt/postgresql/*.plist ~/Library/LaunchAgents` then to check that it's working after booting do: `ps ax | grep sql`\n\n### PostGIS\n- On Ubuntu do `apt-get install postgis`\n\n- On Mac OS X the easiest method is via homebrew: `brew install postgis`  \n(note that if you don't have Postgres or GDAL installed already it will automatically install these first).\n\n- to install on Windows...\n\n## psql\npsql is the interactive unix command line tool for interacting with Postgres/PostGIS.\n\n### Common Commands\n- log-in / connect to a database name by doing `psql -d db_name`\n\n- for doing admin type things such as managing db users, log in as the postgres user: `psql postgres;`\n\n- to create a database: `CREATE DATABASE database-name;`\n\n- to connect to a database: `\\c database-name;`\n\n- to delete a database `DROP DATABASE database-name;`\n\n- to connect when starting psql use the `-d` flag like: `psql -d nyc_noise`\n\n- to list all databases: `\\l`\n\n- to quit psql: `\\q`\n\n- to grant privileges to a user (requires logging in as `postgres` ):\n\n\t`GRANT ALL PRIVILEGES ON DATABASE mydb TO myuser;`\n\n- to enable the hstore extension ( for key : value pairs, useful when working with OpenStreetMap data) do: `CREATE EXTENSION hstore`\n\n- to view columns of a table: `\\d table_name`\n\n- to list all columns in a table (helpful when you have a lot of columns!):  \n  `select column_name from information_schema.columns where table_name = 'my_table' order by column_name asc;`\n\n- to rename a column:  \n  `alter table noise.hoods rename column noise_sqkm to complaints_sqkm;`\n\n- to change a column's data type:  \n  `alter table noise.hoods alter column noise_area type float;`\n\n- to compute values from two columns and assign them to another column: `update noise.hoods set noise_area = noise/(area/1000);`\n\n- to search by wildcard use the `like` (case sensitive) or `ilike` (treats everything as lowercase) command:   \n  `SELECT count(*) from violations where inspection_date::text ilike '2014%';`\n\n- to insert data into a table:  \n\n  ```\n  INSERT INTO table_name (column1, column2)\n  VALUES\n  \t(value1, value2);\n  ```\n\n- to insert data from another table:\n\n  ```\n  INSERT INTO table_name (value1, value2)\n  SELECT column1, column2\n  FROM other_table_name\n  ```\n\n\n- to remove rows using a where clause:  \n  `DELETE FROM table_name WHERE some_column = some_value`\n\n\n- **list all column names from a table in alphabetical order:**  \n\n  ```\n  select column_name\n  from information_schema.columns\n  where table_schema = 'public'\n  and table_name = 'bk_pluto'\n  order by column_name;\n  ```\n\n- **List data from a column as a single row, comma separated:**\n  1. `SELECT array_to_string( array( SELECT id FROM table ), ',' )`  \n  2.  `SELECT string_agg(id, ',') FROM table`\n\n- **rename an existing table:**  \n  `ALTER TABLE table_name RENAME TO table_name_new;`\n\n- **rename an existing column** of a table:  \n  `ALTER TABLE table_name RENAME COLUMN column_name TO column_new_name;`\n\n- **Find duplicate rows** in a table based on values from two fields:\n\n\t```\n\tselect * from (\n\t  SELECT id,\n\t  ROW_NUMBER() OVER(PARTITION BY merchant_Id, url ORDER BY id asc) AS Row\n\t  FROM Photos\n\t) dups\n\twhere\n\tdups.Row \u003e 1\n\t```\n\tcredit: [MatthewJ on stack-exchange](http://stackoverflow.com/questions/14471179/find-duplicate-rows-with-postgresql)\n\n- **Bulk Queries** are efficient when doing multiple inserts or updates of different values:\n\n\t```\n\tUPDATE election_results o\n\tSET votes=n.votes, pro=n.pro\n\tFROM (VALUES (1,11,9),\n\t             (2,44,28),\n\t             (3,25,4)\n\t      ) n(county_id,votes,pro)\n\tWHERE o.county_id = n.county_id;\n\t```\n\n\t```\n\tINSERT INTO election_results (county_id,voters,pro)\n\tVALUES  (1, 11,8),\n\t        (12,21,10),\n\t        (78,31,27);    \n    ```\n    ```\n\tWITH\n\t-- write the new values\n\tn(ip,visits,clicks) AS (\n\t  VALUES ('192.168.1.1',2,12),\n\t         ('192.168.1.2',6,18),\n\t         ('192.168.1.3',3,4)\n\t),\n\t-- update existing rows\n\tupsert AS (\n\t  UPDATE page_views o\n\t  SET visits=n.visits, clicks=n.clicks\n\t  FROM n WHERE o.ip = n.ip\n\t  RETURNING o.ip\n\t)\n\t-- insert missing rows\n\tINSERT INTO page_views (ip,visits,clicks)\n\tSELECT n.ip, n.visits, n.clicks FROM n\n\tWHERE n.ip NOT IN (\n\t  SELECT ip FROM upsert\n\t);    \n\t```\n### Importing Data\n- import data from a CSV file using the COPY command:  \n\n\t```\n\tCOPY noise.locations (name, complaint, descript, boro, lat, lon)\n\tFROM '/Users/chrislhenrick/tutorials/postgresql/data/noise.csv' WITH CSV HEADER;\n\t```\n- import a CSV file \"AS IS\" using csvkit's `csvsql` (requires python, pip, csvkit, psycopg2):\n\n\t```\n\tcsvsql --db postgresql:///nyc_pluto --insert 2012_DHCR_Bldg.csv\n\t```\n\n### Exporting Data\n- export data as a CSV with Headers using COPY:\n\n\t```\n\tCOPY dob_jobs_2014 to '/Users/chrislhenrick/development/nyc_dob_jobs/data/2014/dob_jobs_2014.csv' DELIMITER ',' CSV Header;\n\t```\n\n- to the current workspace without saving to a file:\n\n\t```\n\tCOPY (SELECT foo FROM bar) TO STDOUT CSV HEADER;\n\t```\n\n- from the command line w/o connecting to postgres:\n\n\t```\n\tpsql -d dbname -t -A -F\",\" -c \"select * from table_name\" \u003e output.csv\n\t```\n\n\n### Joining Tables Using a Shared Key\nFrom CartoDB's tutorial [Join data from two tables using SQL](http://docs.cartodb.com/tutorials/joining_data.html)\n\n- Join two tables that share a key using an `INNER JOIN`(Postgresql's default join type):\n\n\t```\n\tSELECT table_1.the_geom,table_1.iso_code,table_2.population\n\tFROM table_1, table_2\n\tWHERE table_1.iso_code = table_2.iso\n\t```\n\n- To update a table's data based on that of a join:\n\n\t```\n\tUPDATE table_1 as t1\n\tSET population = (\n\t  SELECT population\n\t  FROM table_2\n\t  WHERE iso = t1.iso_code\n\t  LIMIT 1\n\t)\n\t```\n\n- aggregate data on a join (if table 2 has multiple rows for a unique identifier):\n\n\t```\n\tSELECT\n\t  table_1.the_geom,\n\t  table_1.iso_code,\n\t  SUM(table_2.total) as total\n\tFROM table_1, table_2\n\tWHERE table_1.iso_code = table_2.iso\n\tGROUP BY table_1.iso_code, table_2.iso\n\t```\n- update the value of a column based on the aggregate join:\n\n\t```\n\tUPDATE table_1 as t1\n\tSET total =  (\n\t  SELECT SUM(total)\n\t  FROM table_2\n\t  WHERE iso = t1.iso_code\n\t  GROUP BY iso\n\t)\n\t```\n\n### Upgrading Postgres\n[This Tutorial](http://blog.55minutes.com/2013/09/postgresql-93-brew-upgrade/) was very helpful for upgrading on Mac OS X via homebrew.\n\n**_WARNING:_** **Back up your data before doing this incase you screw up like I did!**\n\nBasically the steps are:  \n\n1. Shut down Postgresql:  \n\t`launchctl unload ~/Library/LaunchAgents/homebrew.mxcl.postgresql.plist`\n\n2. Create a new Postgresql9.x data directory:  \n\t`initdb /usr/local/var/postgres9.4 -E utf8`\n\n3. Run the pg_upgrade command:\n\n\t```\n\tpg_upgrade \\\n\t-d /usr/local/var/postgres \\\n\t-D /usr/local/var/postgres9.4 \\\n\t-b /usr/local/Cellar/postgresql/9.3.5_1/bin/ \\\n\t-B /usr/local/Cellar/postgresql/9.4.0/bin/ \\\n\t-v\n\t```\n4. Change kernel settings if necessary:\n\n\t```\n\tsudo sysctl -w kern.sysv.shmall=65536\n\tsudo sysctl -w kern.sysv.shmmax=16777216\n\t```  \n\t- I also ran sudo vi /etc/sysctl.conf and entered the same values:\n\n\t```\n\tkern.sysv.shmall=65536\n\tkern.sysv.shmmax=16777216\n\t```\n\t- re-run the pg_upgrade command in step 3\n\n5. Move the new data directory into place:\n\n\t```\n\tcd /usr/local/var\n\tmv postgres postgres9.2.4\n\tmv postgres9.3 postgres\n\t```\n6. Start the new version of PostgreSQL:\n\t `launchctl load -w ~/Library/LaunchAgents/homebrew.mxcl.postgresql.plist`  \n   - check to make sure it worked:\n\n   ```\n   psql postgres -c \"select version()\"\n   psql -l\n   ```\n\n7. Cleanup:  \n\t- `vacuumdb --all --analyze-only`  \n\t- `analyze_new_cluster.sh`*  \n\t- `delete_old_cluster.sh`*\n\t- `brew cleanup postgresql`  \n\t(* scripts were generated in same the directory where `pg_upgrade` was ran)\n\n\n## PostGIS\nPostGIS is the extension for Postgres that allows for working with geometry data types and doing GIS operations in Postgres.\n\n### Common Commands\n\n- to enable PostGIS in a Postgres database do: `CREATE EXTENSION postgis;`\n\n- to enable PostGIS topology do: `CREATE EXTENSION postgis_topology;`\n\n- to support OSM tags do: `CREATE EXTENSION hstore;`\n\n- create a new table for data from a CSV that has lat and lon columns:\n\n  ```\n  create table noise.locations\n  (                                     \n\tname varchar(100),\n\tcomplaint varchar(100), descript varchar(100),\n\tboro varchar(50),\n\tlat float8,\n\tlon float8,\n\tgeom geometry(POINT, 4326)\n  );\n  ```\n\n- inputing values for the geometry type after loading data from a CSV:  \n`update noise.locations set the_geom = ST_SetSRID(ST_MakePoint(lon, lat), 4326);`\n\n- adding a geometry column in a non-spatial table:  \n  `select addgeometryColumn('table_name', 'geom', 4326, 'POINT', 2);`\n\n- calculating area in EPSG 4326:  \n  `alter table noise.hoods set area = (select ST_Area(geom::geography));`\n\n\n### Common Spatial Queries\nYou may view more of these in [my intro to Visualizing Geospatial Data with CartoDB](https://github.com/clhenrick/cartodb-tutorial/tree/master/sql).\n\n**Find all polygons from dataset A that intersect points from dataset B:**\n\n```\nSELECT a.*\nFROM table_a_polygons a, table_b_points b\nWHERE ST_Intersects(a.the_geom, b.the_geom);\n```\n\n**Find all rows in a polygon dataset that intersect a given point:**\n\n```\n-- note: geometry for point must be in the order lon, lat (x, y)\nSELECT * FROM nyc_tenants_rights_service_areas\nwhere\nST_Intersects(\n  ST_GeomFromText(\n   'Point(-73.982557 40.724435)', 4326\n  ),\n  nyc_tenants_rights_service_areas.the_geom    \n);\n```\n\nOr using `ST_Contains`:\n\n```\nSELECT * FROM nyc_tenants_rights_service_areas\nwhere\nst_contains(\n  nyc_tenants_rights_service_areas.the_geom,\n  ST_GeomFromText(\n   'Point(-73.917104 40.694827)', 4326\n  )      \n);\n```\n\n**Counting points inside a polygon:**\n\nWith ST_Containts():\n\n```\nSELECT us_counties.the_geom_webmercator,us_counties.cartodb_id,\ncount(quakes.the_geom)\nAS total\nFROM us_counties JOIN quakes\nON st_contains(us_counties.the_geom,quakes.the_geom)\nGROUP BY us_counties.cartodb_id;\n```\n\nTo update a column from table A with the number of points from table B that intersect table A's polygons:  \n\n```\nupdate noise.hoods set num_complaints = (\n\tselect count(*)\n\tfrom noise.locations\n\twhere\n\tST_Intersects(\n\t\tnoise.locations.geom,\n\t\tnoise.hoods.geom\n\t)\n);\n```\n\n**Select data within a bounding box**  \nUsing [`ST_MakeEnvelope`](http://postgis.refractions.net/docs/ST_MakeEnvelope.html)\n\nHINT: You can use [bboxfinder.com](http://bboxfinder.com/) to easily grab coordinates\nof a bounding box for a given area.\n\n```\nSELECT * FROM some_table\nwhere geom \u0026\u0026 ST_MakeEnvelope(-73.913891, 40.873781, -73.907229, 40.878251, 4326)\n```\n\n**Make a line from a series of points**\n\n```\nSELECT ST_MakeLine (the_geom ORDER BY id ASC)\nAS the_geom, route\nFROM points_table\nGROUP BY route;\n```\n\n**Order points in a table by distance to a given lat lon**  \nThis one uses CartoDB's built-in function `CDB_LatLng` which is short hand for doing:  \n`SELECT ST_Transform( ST_GeomFromText( 'Point(-73.982557 40.724435)',),4326)`\n\n```\nSELECT * FROM table\nORDER BY the_geom \u003c-\u003e\nCDB_LatLng(42.5,-73) LIMIT 10;\n```\n\n**Access the previous row of data and get value (time, value, number, etc) difference**\n\n```\nWITH calc_duration AS (\n SELECT\n cartodb_id,\n extract(epoch FROM (date_time - lag(date_time,1) OVER(ORDER BY date_time))) AS\nduration_in_seconds\n FROM tracking_eric\n ORDER BY date_time\n)\nUPDATE tracking_eric\nSET duration_in_seconds = calc_duration.duration_in_seconds\nFROM calc_duration\nWHERE calc_duration.cartodb_id = tracking_eric.cartodb_id\n```\n\n**select population density by county**\n\nIn this one we cast the geometry data type to the geography data type to get units of measure in meters.\n\n```\nSELECT pop_sqkm,\n round( pop / (ST_Area(the_geom::geography)/1000000))\n as psqkm\n FROM us_counties\n```\n\n\n### Spatial Indexing\nMakes queries hella fast. [OSGeo](http://revenant.ca/www/postgis/workshop/indexing.html) has a good tutorial.\n\n- Basically the steps are:  \n  `CREATE INDEX table_name_gix ON table_name USING GIST (geom);`  \n  `VACUUM ANALYZE table_name`  \n  `CLUSTER table_name USING table_name_gix;`  \n  ***Do this every time after making changes to your dataset or importing new data.**\n\n### Importing Spatial Data to PostGIS\n#### Using shp2pgsql\n1. Do:  \n`shp2pgsql -I -s 4326 nyc-pediacities-hoods-v3-edit.shp noise.hoods \u003e noise.sql`  \nOr for using the geography data type do:  \n`shp2pgsql -G -I nyc-pediacities-hoods-v3-edit.shp noise.nyc-pediacities-hoods-v3-edit_geographic \u003e nyc_pediacities-hoods-v3-edit.sql`\n\n2. Do:  \n`psql -d nyc_noise -f noise.sql`  \nOr for the geography type above:  \n`psql -d nyc_noise -f nyc_pediacities-hoods-v3-edit.sql `\n\n#### Using osm2pgsql\nTo import an OpenStreetMap extract in PBF format do:  \n`osm2pgsql -H localhost --hstore-all -d nyc_from_osm ~/Downloads/newyorkcity.osm.pbf`\n\n#### Using ogr2ogr\nExample importing a GeoJSON file into a database called nyc_pluto:  \n\n```\nogr2ogr -f PostgreSQL \\\nPG:\"host='localhost' user='chrislhenrick' port='5432' \\\ndbname='nyc_pluto' password=''\" \\\nbk_map_pluto_4326.json -nln bk_pluto\n```\n\n\n### Exporting Spatial Data from PostGIS\nThe two main tools used to export spatial data with more complex geometries from Postgres/PostGIS than points are `pgsql2shp` and `ogr2ogr`.\n\n#### Using pgsql2shp\n`pgsql2shp` is a tool that comes installed with PostGIS that allows for exporting data from a PostGIS database to a shapefile format. To use it you need to specify a file path to the output shapefile (just stating the basename with no extension will output in the current working directory), a host name (usually this is `localhost`), a user name, a password for the user, a database name, and an SQL query.\n\n```\npgsql2shp -f \u003cpath to output shapefile\u003e -h \u003chostname\u003e -u \u003cusername\u003e -P \u003cpassword\u003e databasename \"\u003cquery\u003e\"\n```\n\nA sample export of a shapefile called `my_data` from a database called `my_db` looks like this:\n\n```\npgsql2shp -f my_data -h localhost -u clhenrick -P 'mypassword' my_db \"SELECT * FROM my_data \"\n```\n\n#### Using ogr2ogr\n**Note:** You may need to set the `GDAL_DATA` path if you git this error:\n\n```\nERROR 4: Unable to open EPSG support file gcs.csv.\nTry setting the GDAL_DATA environment variable to point to the\ndirectory containing EPSG csv files.\n```\nIf on Linux / Mac OS do this: `export GDAL_DATA=/usr/local/share/gdal`  \nIf on Windows do this: `C:\\\u003e set GDAL_DATA=C:\\GDAL\\data`\n\n**To Export Data**  \nUse ogr2ogr as follows to export a table (in this case a table called `dob_jobs_2014`) to a `GeoJSON` file (in this case a file called dob_jobs_2014_geocoded.geojson):\n\n```\nogr2ogr -f GeoJSON -t_srs EPSG:4326 dob_jobs_2014_geocoded.geojson \\\nPG:\"host='localhost' dbname='dob_jobs' user='chrislhenrick' password='' port='5432'\" \\\n-sql \"SELECT bbl, house, streetname, borough, jobtype, jobstatus, existheight, proposedheight, \\\nexistoccupancy, proposedoccupany, horizontalenlrgmt, verticalenlrgmt, ownerbusinessname, \\\nownerhousestreet, ownercitystatezip, ownerphone, jobdescription, geom \\\nFROM dob_jobs_2014 WHERE geom IS NOT NULL\"\n```\n\n- **note:** you must select the column containing the geometry (usually `geom` or `wkb_geometry`) for your exported layer to have geometry data.\n\n## Other Methods of Interacting With Postgres/PostGIS\nto do...\n### PGAdmin\n\n### Python\n\n### Node JS\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fclhenrick%2Fpostgresql_postgis_cheatsheet","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fclhenrick%2Fpostgresql_postgis_cheatsheet","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fclhenrick%2Fpostgresql_postgis_cheatsheet/lists"}