Thread: Expression alias not recognized in WHERE clause (ERROR: relation "p" does not exist)
Expression alias not recognized in WHERE clause (ERROR: relation "p" does not exist)
From
Stefan Keller
Date:
Hi I have two (hopefully) equivalent - and unfortunately very slow - queries which "Select all buildings that have >1 pharmacies and >1 schools within 1000m". In the first query there is an expression alias "b" and in the second there are two expression aliases: "b" and "p". Can someone tell me, why expression alias "p" is *not* recognized in the WHERE clause - whereas alias "b" is (parantheses missing)? And, has anyone an idea on how to reformulate this second query? Stefan SELECT way AS building_geometry FROM (SELECT osm_id, way FROM osm_polygon WHERE tags @> hstore('building','yes') ) AS b WHERE (SELECT count(*) > 1 FROM osm_poi AS p WHERE p.tags @> hstore('amenity','pharmacy') AND ST_DWithin(b.way,p.way,1000) ) AND (SELECT count(*) > 1 FROM osm_poi AS p WHERE p.tags @> hstore('amenity','school') AND ST_DWithin(b.way,p.way,1000) ) SELECT b.way AS building_geometry FROM (SELECT way FROM osm_polygon WHERE tags @> hstore('building','yes') ) AS b, (SELECT way, tags->'amenity' as value FROM osm_poi WHERE (tags ? 'amenity') ) AS p WHERE (SELECT count(*) > 1 FROM p WHERE p.value = 'pharmacy' AND ST_DWithin(b.way,p.way,1000) ) AND (SELECT count(*) > 1 FROM p WHERE p.value = 'school' AND ST_DWithin(b.way,p.way,1000) ) ERROR: relation "p" does not exist LINE 10: (SELECT count(*) > 1 FROM p ^ ********** Error ********** ERROR: relation "p" does not exist SQL state: 42P01 Character: 245
Re: Expression alias not recognized in WHERE clause (ERROR: relation "p" does not exist)
From
Alban Hertroys
Date:
> SELECT b.way AS building_geometry > FROM > (SELECT way FROM osm_polygon > WHERE tags @> hstore('building','yes') > ) AS b, > (SELECT way, tags->'amenity' as value FROM osm_poi > WHERE (tags ? 'amenity') > ) AS p > WHERE > (SELECT count(*) > 1 FROM p > WHERE p.value = 'pharmacy' > AND ST_DWithin(b.way,p.way,1000) > ) > AND > (SELECT count(*) > 1 FROM p > WHERE p.value = 'school' > AND ST_DWithin(b.way,p.way,1000) > ) > > ERROR: relation "p" does not exist > LINE 10: (SELECT count(*) > 1 FROM p You're referencing "p" as a table, not as a table-alias, because you select FROM p. 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. 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. 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. -- If you can't see the forest for the trees, Cut the trees and you'll see there is no forest.
Re: Expression alias not recognized in WHERE clause (ERROR: relation "p" does not exist)
From
"Tomas Vondra"
Date:
On 9 Srpen 2012, 13:32, Stefan Keller wrote: > Hi > > I have two (hopefully) equivalent - and unfortunately very slow - queries > which > "Select all buildings that have >1 pharmacies and >1 schools within > 1000m". > > In the first query there is an expression alias "b" and in the second > there are two expression aliases: "b" and "p". > > Can someone tell me, why expression alias "p" is *not* recognized in > the WHERE clause - whereas alias "b" is (parantheses missing)? > > And, has anyone an idea on how to reformulate this second query? > > Stefan > > > SELECT way AS building_geometry > FROM > (SELECT osm_id, way > FROM osm_polygon > WHERE tags @> hstore('building','yes') > ) AS b > WHERE > (SELECT count(*) > 1 FROM osm_poi AS p > WHERE p.tags @> hstore('amenity','pharmacy') > AND ST_DWithin(b.way,p.way,1000) > ) > AND > (SELECT count(*) > 1 FROM osm_poi AS p > WHERE p.tags @> hstore('amenity','school') > AND ST_DWithin(b.way,p.way,1000) > ) > > > SELECT b.way AS building_geometry > FROM > (SELECT way FROM osm_polygon > WHERE tags @> hstore('building','yes') > ) AS b, > (SELECT way, tags->'amenity' as value FROM osm_poi > WHERE (tags ? 'amenity') > ) AS p > WHERE > (SELECT count(*) > 1 FROM p > WHERE p.value = 'pharmacy' > AND ST_DWithin(b.way,p.way,1000) > ) > AND > (SELECT count(*) > 1 FROM p > WHERE p.value = 'school' > AND ST_DWithin(b.way,p.way,1000) > ) > > ERROR: relation "p" does not exist > LINE 10: (SELECT count(*) > 1 FROM p > ^ > > ********** Error ********** > > ERROR: relation "p" does not exist > SQL state: 42P01 > Character: 245 Well, that's pretty clear why it does not recognize the "p" alias in the subquery - you're trying to do a SELECT from it, and it can't use the alias like this. You can reference it in a condition (as you do with the "b") but you can't do a SELECT. You could do is use CTEs to do that, e.g. like this: WITH b AS (SELECT way FROM osm_polygon WHERE tags @> hstore('building','yes')), p AS (SELECT way, tags->'amenity' as value FROM osm_poi WHERE (tags ? 'amenity') SELECT b.way AS building_geometry FROM b WHERE ( SELECT count(*) > 1 FROM p WHERE p.value = 'pharmacy' AND ST_DWithin(b.way,p.way,1000) ) AND ( SELECT count(*) > 1 FROM p WHERE p.value = 'school' AND ST_DWithin(b.way,p.way,1000) ) That should work. Still, I believe you could use INTERSECT to handle this - I haven't noticed the '>' in the original post and I've treated it like '>=', but I believe the query may be easily tweaked to handle this. See this: SELECT b.osm_id FROM osm_poi AS p, osm_polygon b WHERE p.tags @> hstore('amenity','pharmacy') AND b.tags @> hstore('building','yes') AND ST_DWithin(b.way,p.way,1000) GROUP BY b.osm_id HAVING COUNT(*) > 1 INTERSECT SELECT b.osm_id FROM osm_poi AS p, osm_polygon b WHERE p.tags @> hstore('amenity','school') AND b.tags @> hstore('building','yes') AND ST_DWithin(b.way,p.way,1000) GROUP BY b.osm_id HAVING COUNT(*) > 1 regards Tomas
Re: Expression alias not recognized in WHERE clause (ERROR: relation "p" does not exist)
From
David Johnston
Date:
On Aug 9, 2012, at 7:32, Stefan Keller <sfkeller@gmail.com> wrote: > Hi > > I have two (hopefully) equivalent - and unfortunately very slow - queries which > "Select all buildings that have >1 pharmacies and >1 schools within 1000m". > > In the first query there is an expression alias "b" and in the second > there are two expression aliases: "b" and "p". > > Can someone tell me, why expression alias "p" is *not* recognized in > the WHERE clause - whereas alias "b" is (parantheses missing)? The subqueries can make use of values attached to the outer (aliased) relation but you cannot use the alias itself as a FROMsource. The error is stemming from your use of "FROM p" inside the WHERE. > > And, has anyone an idea on how to reformulate this second query? Use a common table expression (CTE) (sql command: WITH). Those can be attached to any FROM clause in the query. > > Stefan > > > SELECT way AS building_geometry > FROM > (SELECT osm_id, way > FROM osm_polygon > WHERE tags @> hstore('building','yes') > ) AS b > WHERE > (SELECT count(*) > 1 FROM osm_poi AS p > WHERE p.tags @> hstore('amenity','pharmacy') > AND ST_DWithin(b.way,p.way,1000) > ) > AND > (SELECT count(*) > 1 FROM osm_poi AS p > WHERE p.tags @> hstore('amenity','school') > AND ST_DWithin(b.way,p.way,1000) > ) > > > SELECT b.way AS building_geometry > FROM > (SELECT way FROM osm_polygon > WHERE tags @> hstore('building','yes') > ) AS b, > (SELECT way, tags->'amenity' as value FROM osm_poi > WHERE (tags ? 'amenity') > ) AS p > WHERE > (SELECT count(*) > 1 FROM p > WHERE p.value = 'pharmacy' > AND ST_DWithin(b.way,p.way,1000) > ) > AND > (SELECT count(*) > 1 FROM p > WHERE p.value = 'school' > AND ST_DWithin(b.way,p.way,1000) > ) > > ERROR: relation "p" does not exist > LINE 10: (SELECT count(*) > 1 FROM p > ^ > > ********** Error ********** > > ERROR: relation "p" does not exist > SQL state: 42P01 > Character: 245 > > -- > Sent via pgsql-general mailing list (pgsql-general@postgresql.org) > To make changes to your subscription: > http://www.postgresql.org/mailpref/pgsql-general
Re: Expression alias not recognized in WHERE clause (ERROR: relation "p" does not exist)
From
Stefan Keller
Date:
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@gmail.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
Re: Expression alias not recognized in WHERE clause (ERROR: relation "p" does not exist)
From
Alban Hertroys
Date:
On 13 Aug 2012, at 1:15, Stefan Keller wrote: > 2012/8/9 Alban Hertroys <haramrae@gmail.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. I don't think SQL allowed re-referencing an earlier mentioned table like that until CTE's were introduced to take care ofit instead. Not sure what's behind that. Normally people only use table aliases to have easier access to columns in a specific table in their query. Additionally,aliases are sometimes required to disambiguate which instance of the same table in a join is meant. Perhapsthere are other users still, but using an alias as a table to select from is not among them I'm afraid. >> 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). Ah yes, you're correct about that. > 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... A start would be to post an explain analyse (or a link to the results from http://explain.depesz.com/). It's possible that you can about half that time by using something like this instead of the separate pharmacy and schoolexpressions (I haven't used hstore before, so I may have made an error or two): nr_by_type AS ( SELECT way, SUM(CASE WHEN tags.value = 'pharmacy' THEN 1 ELSE 0 END) AS nr_pharmacies, SUM(CASE WHEN tags.value = 'school' THEN 1 ELSE 0 END) AS nr_schools FROM osm_poi WHERE tags.key = 'amenity' GROUP BY way ) But that's just a guess on my part of where the bottleneck is. Alban Hertroys -- Screwing up is an excellent way to attach something to the ceiling.