Question

I have a PostGIS query where I really need to have nested queries inside PostGIS function calls:

UPDATE raw.geocoding
SET the_geom = ST_Centroid(
   ST_Collect(
     SELECT the_geom
     FROM raw.geocoding
     WHERE hash = ((E'0101000020090C000081610F9CC5DC3341EE672E6E723B3241')::varchar),
     SELECT the_geom
     FROM raw.geocoding
     WHERE hash = ((E'0101000020090C00002CF887E0C5DC3341C9E5B2DF2A383241')::varchar)
    )
  )
WHERE hash = ((E'3e638a27c6c38f05026252f4a0b57b2e')::varchar)

Unfortunately, this doesn't work. I get a syntax error at the beginning of the nested query:

ERROR:  syntax error at or near "SELECT"
LINE 4:          SELECT the_geom
                 ^

********** Error **********

ERROR: syntax error at or near "SELECT"
SQL state: 42601
Character: 86

Looks like I cannot have a nested query as a PostGIS function parameter?

I've perused through the PostGIS documentation and cannot find any clear guidance for dealing with this.

It appears Postgres has a way of doing variables in pgSQL, but it's unclear to me how this would be pulled off in a standard query. This is a query that will be run tens or hundreds of thousands of times from a C# program. That aside, I could do a pgSQL stored procedure if required; just wanted to make sure there wasn't a simpler alternative first.

In case you were wondering, the query looks messy because it's the result of a npgsql-generated parameterized query. I think it's fair to say that npgsql is being extra-cautious with redundant typing and escaping.

I am running PostGIS 2.0.1, Postgres 9.1.5, and npgsql 2.0.12.

Was it helpful?

Solution

It sounds like you want a scalar subquery, an expression written like (SELECT ....) (note enclosing parentheses) that contains a query returning either zero rows (NULL result) or one field from one row.

You were most of the way there, you just needed the parens:

UPDATE raw.geocoding
SET the_geom = ST_Centroid(
   ST_Collect(
     (SELECT the_geom
     FROM raw.geocoding
     WHERE hash = ((E'0101000020090C000081610F9CC5DC3341EE672E6E723B3241')::varchar)),
     (SELECT the_geom
     FROM raw.geocoding
     WHERE hash = ((E'0101000020090C00002CF887E0C5DC3341C9E5B2DF2A383241')::varchar))
    )
  )
WHERE hash = ((E'3e638a27c6c38f05026252f4a0b57b2e')::varchar)

Note that subqueries can be used in other places too - table returning subqueries can appear in FROM, for example. The PostgreSQL manual teaches about all this, and is well worth a cover-to-cover read.

If you're doing a lot of these updates, you may find it more efficient to formulate the UPDATE as a join using the PostgreSQL extension UPDATE ... FROM ... WHERE rather than running lots of individual UPDATEs over and over. I just wanted to raise the possibility. See from-list in UPDATE

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top