"SELECT ... AS ..." - column ... does not exist

Hallo Forum,

nach langer Zeit mal wieder eine Frage, zu der ich keine Lösung finde.
Folgendes:

SELECT a, b, c, (a+b+c) as d FROM t_table WHERE d > 0 ORDER BY d

…wirft die Fehlermeldung

column "d" does not exist

Bei MySQL ist das kein Problem und als ich vor 25 Jahren SQL im Studium kennengelernt habe, wurden obige Konstrukte häufig verwendet.
Interessant daran ist auch, wenn ich WHERE… weglasse, gibt es keine Fehlermeldung,

Für eine Antwort immer dankbar

JueDan

Ja, das KANN so nicht gehen. Weil erst einmal das WHERE ausgeführt wird, erst DANACH mit dem, was das Where liefert, die Berechnung und das ‘erzeugen’ der berechneten Spalte. Also, zu dem Zeitpunkt, wo das WHERE die Zeilen filtert, gibt es ‘d’ noch nicht. Also: statt d im Where den ganzen Ausdruck, der zu d wird.

btw.:

mysql> create table foo (a int, b int, c int);
ERROR 1050 (42S01): Table 'foo' already exists
mysql> drop table foo;
Query OK, 0 rows affected (0,02 sec)

mysql> create table foo (a int, b int, c int);
Query OK, 0 rows affected (0,02 sec)

mysql> select a,b,c,a+b+c as d from foo where d = 10;
ERROR 1054 (42S22): Unknown column 'd' in 'where clause'
mysql>

was du machen kannst:

test=*# create table foo (a int, b int, c int);
CREATE TABLE
test=*# 
test=*# select a,b,c,a+b+c as d from foo where d = 10;
FEHLER:  Spalte »d« existiert nicht
LINE 1: select a,b,c,a+b+c as d from foo where d = 10;
                                               ^
test=*# with x as (select a,b,c,a+b+c as d from foo) select * from x where d = 10;
 a | b | c | d 
---+---+---+---
(0 rows)

test=*#

ACHTUNG: das ist aus Performance-Sicht ein Desaster, da x zuerst materialisiert wird. Daher besser:

test=*# select a,b,c,a+b+c as d from foo where a+b+c = 10;
 a | b | c | d 
---+---+---+---
(0 rows)

test=*# create index idx_abc on foo ((a+b+c));
CREATE INDEX
test=*# explain select a,b,c,a+b+c as d from foo where a+b+c = 10;
                              QUERY PLAN                               
-----------------------------------------------------------------------
 Bitmap Heap Scan on foo  (cost=4.23..14.89 rows=10 width=12)
   Recheck Cond: (((a + b) + c) = 10)
   ->  Bitmap Index Scan on idx_abc  (cost=0.00..4.23 rows=10 width=0)
         Index Cond: (((a + b) + c) = 10)
(4 rows)

test=*#

das kann so sogar den Index nutzen.

Guten Abend akretschmer,

danke für die Antwort.
Jetzt ist es mir auch klar, bin halt doch etwas aus der Übung.

Bei der MySQL-Sache habe ich mich vertan. Statt WHERE habe ich dort HAVING, war ein klassischer Copy&Paste-Fehler. Aber das geht bei PG auch nicht.

Nach etwas tiefer gehender Überlegung habe ich das Problem so gelöst:
SELECT a,b,c, (a+b+c) as d FROM table ORDER BY d

Hintergrund der Geschichte ist, dass ich eine Tabelle mit Einträgen zu Webcams habe. Diese sollen im Umkreis von 30km liegen und nach ihrer Entfernung sortiert ausgegeben werden:

SELECT standort,url,bildurl,copyright,copyright_url,Webcam_Distanz(%f,%f,lat,lon) AS distanz 
FROM t_webcams 
WHERE bildurl != '' AND aktiv = 1 
ORDER BY distanz ASC
LIMIT 6

(%f ist der Standort, in dessen Nähe die Cams stehen sollen)

Das Problem dieser Methode ist halt, dass auch Webcams angezeigt werden können, die jenseits des 30km-Radius liegen. Das erledige ich jetzt aber im PHP-Skript.

Beste Grüße

JueDan

PS: Die zugehörige Funktion

CREATE OR REPLACE FUNCTION webcam_distanz(double precision, double precision, double precision, double precision)
  RETURNS double precision AS
$BODY$
 SELECT (6371 * acos(sin($1/57.295800) * sin($3/57.295800) +
        cos($1/57.295800) * cos($3/57.295800) * 
        cos($4/57.295800 - $2/57.295800))) AS result;
$BODY$
  LANGUAGE sql VOLATILE
  COST 100;

Für alles was mit Geo-Daten zu tun hat, nimmst Du besser PostGIS - da kann man das mit der Entfernung dann auch vernünftig indizieren, damit es schnell wird.

Deine webcam_distanz() sollest Du als “immutable” definieren. volatile ist für die Funktion die falsche Einstellung

:wink: @castorp

Guten Abend castorp

anfangs wollte ich auch PostGIS nehmen. Auf meinem privaten Server kein Problem, aber mein Webspace ist mit MySQL ausgestattet…
An meinem privaten PostgreSQL-Server hängt noch mein DaviCAL - deswegen diese seltsame Konstellation.

Danke für den Tipp mit “immutable” - habe ich geändert.

Schönen Abend noch

JueDan

Vielleicht findest du da Hilfe, MySQL kann auch was mit Geometrien:

https://dev.mysql.com/doc/refman/8.0/en/gis-property-functions.html

Mea culpa, ich poste einen MySQL-Link in ein Postgres-Forum :wink:

Viele Grüße Uwe

Sodele, zurück zu meiner Frage:

SELECT standort,url,bildurl,copyright,copyright_url,Webcam_Distanz(47.6,12.2,lat,lon) AS distanz
FROM t_webcams
HAVING bildurl != ‘’ AND aktiv = 1 AND distanz < 30.0
ORDER BY distanz ASC
LIMIT 6

PG wirft hier als Fehler

ERROR: column "distanz" does not exist
SQL Status:42703

Warum, wieso, weshalb?

HAVING dient als Filter auf Ergebnisse NACH einer Aggregation. Du hast keine Aggregation.

Moin,
das Problem habe ich jetzt im PHP-Skript gelöst, indem ich mir sechs Webcams ausgeben lasse und schaue, welche innerhalb des Radius von 30km liegen. Sollte man eigentlich in einer SQL-Abfrage auch schaffen - zumindest habe ich es vor 25 Jahren im Informatikstudium mal so gelernt, aber ist ja jetzt auch wurscht.

Grüße und schöne Weihnachten

JueDan

sicher geht das in SQL, in PostgreSQL sogar indexbasiert, Stichwort KNN. Mit passenden Datentypen und einem GiST-Index.