Re: Expression alias not recognized in WHERE clause (ERROR: relation "p" does not exist)

From: Stefan Keller <sfkeller(at)gmail(dot)com>
To: Alban Hertroys <haramrae(at)gmail(dot)com>
Cc: pgsql-general List <pgsql-general(at)postgresql(dot)org>
Subject: Re: Expression alias not recognized in WHERE clause (ERROR: relation "p" does not exist)
Date: 2012-08-12 23:15:15
Message-ID: CAFcOn29wSyZMTqXn_jLDszyMG-gV0NZitUPwRkY+FT5c2cU3Hw@mail.gmail.com
Views: Raw Message | Whole Thread | Download mbox | Resend email
Thread:
Lists: pgsql-general

Salut Alban

Thanks for your patient hints.
As your signature suggests, I probably could not see the forest for the trees.
But now I think I do (see below) - except for the following:

2012/8/9 Alban Hertroys <haramrae(at)gmail(dot)com> wrote:
> You're referencing "p" as a table, not as a table-alias, because you
> select FROM p.

That's true but sorry that I can see any difference between
referencing a table or a table alias.

> Your join appears to be unconstrained as well: you get every record in
> p for each record in b. That's probably not what you want.

Well, in fact, that was what I wanted and what I finally got with CTE
as you suggested below.

> And you're using WHERE count(*) > 1 where you actually mean WHERE
> EXISTS; you're not interested in the actual count, which is quite a
> bit less efficient to determine than just existence.

That's a good and usual performance hint to test for existence instead
of counting.
But there's one of the challenges of this query:
"Select all buildings that have >1 pharmacies and >1 schools within 1000m".
So it's really forcing a count because it's asking for more than one (not >=1).

> You probably meant to write something like this:
>
> SELECT b.way AS building_geometry
> FROM osm_polygon AS b
> WHERE tags @> hstore('building','yes')
> AND EXISTS (
> SELECT 1 FROM osm_poi AS p
> WHERE p.value = 'pharmacy'
> AND ST_DWithin(b.way,p.way,1000)
> )
> AND EXISTS (
> SELECT 1 FROM osm_poi AS p
> WHERE p.value = 'school'
> AND ST_DWithin(b.way,p.way,1000)
> )
>
> If you're on Postgres 9 then you can put the common osm_poi part in a CTE.

Below you find what I finally got with CTE.
Look at the two "select count(*)>1 which need to be made two times and
contain a count.

WITH
building AS (
SELECT way FROM osm_polygon
WHERE tags @> hstore('building','yes')
--LIMIT 1000
),
pharmacy AS (
SELECT way FROM osm_poi
WHERE tags @> hstore('amenity','pharmacy')
),
school AS (
SELECT way FROM osm_poi
WHERE tags @> hstore('amenity','school')
)
SELECT ST_AsText(building.way) AS building_geometry
FROM building
WHERE
(SELECT count(*) > 1 FROM pharmacy
WHERE ST_DWithin(building.way,pharmacy.way,1000))
AND
(SELECT count(*) > 1 FROM school
WHERE ST_DWithin(building.way,school.way,1000))

I also tried alternatives like:
* "WHERE tags ? 'amenity" which is a kind of tag existence function
* doing a GROUP BY
* or applying a "JOIN .... ON ST_DWithin(building.way,school.way,1000)"
... but no one was as "fast" as this one.

Unfortunately it's still VERY SLOW and takes more than 6 minutes on a
current 72GB memory(!) server!
No idea on how to speed up this tough nut to crack any more...

Yours, Stefan

In response to

Responses

Browse pgsql-general by date

  From Date Subject
Next Message Neanderthelle Jones 2012-08-12 23:28:16 Re: Deleting BLOBs
Previous Message Craig Ringer 2012-08-12 12:53:20 Re: How to raise error from PostgreSql SQL statement if some condition is met