Addieren von Spalten

Hallo,

ich habe einen Query indem über Subquery Spalten mit numerischen Werten erstellt werden. In einer zusätzlichen Spalte soll jetzt die Summe der Werte angezeigt werden.
Ich will die Berechnung allerdings nicht zweimal durchführen, da das den Query langsam machen würde.

Ich habe mir gedacht das es in etwa so Funktioniert:

SELECT (SELECT ...) AS a, (SELECT ...) AS b, (SELECT ...) AS c,(a+b+c)

Leider funktioniert das nicht.
psql sagt column a does not exist.

Natürlich würde es so funktionieren:

SELECT (SELECT ...) AS a, (SELECT ...) AS b, (SELECT ...) AS c,((SELECT ...)+(SELECT ...)+(SELECT ...))

Dadurch werden aber alle Berechnungen zweimal durchgeführt und die Ausführungszeit verdoppelt sich?

Gibt es eine andere schnelle Lösung?

Viele Grüße
cevou

Yes.

Natürlich würde es so funktionieren:

SELECT (SELECT …) AS a, (SELECT …) AS b, (SELECT …) AS c,((SELECT …)+(SELECT …)+(SELECT …))

>

Yes.

> Dadurch werden aber alle Berechnungen zweimal durchgeführt und die Ausführungszeit verdoppelt sich?

No.

> Gibt es eine andere schnelle Lösung?
>
> Viele Grüße
> cevou

No.

Sorry, aber zu der Zeit, wenn der Planner die Plan erstellt, gibt es die Spalten a,b und c nicht. Andererseits kann der Planner erkennen, und tut es auch, daß da Dinge schon berechnet sind.

Genaueres erklärt Dir EXPLAIN.

Andreas

Nachtrag:

Man muß natürlich aufpassen, was man tut. Für Dein Beispiel:

test=*# select * from foo;
 a | b
---+---
 3 | 4
(1 Zeile)

Zeit: 0,290 ms
test=*# explain select (select a * 2 from foo) as a2, (select b * 2 from foo) as b2, (select a*2 + b*2 from foo) as c;
                          QUERY PLAN
---------------------------------------------------------------
 Result  (cost=120.95..120.96 rows=1 width=0)
   InitPlan
     ->  Seq Scan on foo  (cost=0.00..36.75 rows=2140 width=4)
     ->  Seq Scan on foo  (cost=0.00..36.75 rows=2140 width=4)
     ->  Seq Scan on foo  (cost=0.00..47.45 rows=2140 width=8)
(5 Zeilen)

Zeit: 0,388 ms
test=*# explain select a*2 as a2, b*2 as b2, a*2+b*2 as c from foo;
                      QUERY PLAN
-------------------------------------------------------
 Seq Scan on foo  (cost=0.00..58.15 rows=2140 width=8)
(1 Zeile)

Zeit: 0,336 ms

Das die Ausführungszeiten nahezu gleich sind, sollte hier mal nicht beachtet werden, unterschiedlich sind die Pläne. Ich weiß nun nicht, ob Du Dein Select in Form meines zweiten Selects schreiben kannst.

Andreas

Hier einfach mal der komplette Query. Das ganze wird dynamisch erzeugt, weil die Anzahl der Spalten beliebig ist.

SELECT teilnehmerid::text AS platz,
tnname,
vereinname,
substring(to_char(geburtstag,'9999') from 4 for 2),
COALESCE((SELECT round(1*detailswertung::numeric,3) FROM wertungendetails WHERE disziplinid='1' AND wertungendetails.wertungsid=wertungen.wertungsid ORDER BY detailswertung DESC LIMIT 1),0.000),
COALESCE((SELECT round(1*detailswertung::numeric,3) FROM wertungendetails WHERE disziplinid='3' AND wertungendetails.wertungsid=wertungen.wertungsid ORDER BY detailswertung DESC LIMIT 1),0.000),
COALESCE((SELECT round(1*detailswertung::numeric,3) FROM wertungendetails WHERE disziplinid='4' AND wertungendetails.wertungsid=wertungen.wertungsid ORDER BY detailswertung DESC LIMIT 1),0.000),
COALESCE((SELECT round(1*detailswertung::numeric,3) FROM wertungendetails WHERE disziplinid='7' AND wertungendetails.wertungsid=wertungen.wertungsid ORDER BY detailswertung DESC LIMIT 1),0.000),
((COALESCE((SELECT round(1*detailswertung::numeric,3) FROM wertungendetails WHERE disziplinid='1' AND wertungendetails.wertungsid=wertungen.wertungsid ORDER BY detailswertung DESC LIMIT 1),0.000)+COALESCE((SELECT round(1*detailswertung::numeric,3) FROM wertungendetails WHERE disziplinid='3' AND wertungendetails.wertungsid=wertungen.wertungsid ORDER BY detailswertung DESC LIMIT 1),0.000)+COALESCE((SELECT round(1*detailswertung::numeric,3) FROM wertungendetails WHERE disziplinid='4' AND wertungendetails.wertungsid=wertungen.wertungsid ORDER BY detailswertung DESC LIMIT 1),0.000)+COALESCE((SELECT round(1*detailswertung::numeric,3) FROM wertungendetails WHERE disziplinid='7' AND wertungendetails.wertungsid=wertungen.wertungsid ORDER BY detailswertung DESC LIMIT 1),0.000))-0)::numeric AS summe,
wertungen.wertungsid
FROM wertungen
INNER JOIN teilnehmer USING (teilnehmerid)
INNER JOIN vereine USING (vereinid)
INNER JOIN sub_wettkaempfe USING (sub_wettkampfid)
WHERE wettkampfid=12 AND sub_wettkampfnr=1
GROUP BY wertungsid, wertungen.ak, tnname, vereinname, wertungen.teilnehmerid, teilnehmer.geburtstag
ORDER BY wertungen.ak, summe DESC

Da ich mir SQL nur selbst beigebracht habe kann das natürlich auch sein, dass diese Abfrage komplett umständlich ist.
Wenn ich jedenfalls die Summe weglasse ist die Ausführungszeit nur halb so lang.

Viele Grüße

Das NUMERIC dürfte die Sache etwas langsamer machen, weiß aber nicht, wieviel sich das auswirkt. Da du sowieso rundest, bist du anscheinend an sehr exakten Berechnungen nicht interessiert und könntest mit FLOAT oder DOUBLE PRECISION vielleicht etwas Performance gewinnen.

round funktioniert aber leider nur mit numeric. Oder gibts es da eine Alternative für FLOAT oder DOUBLE PRECISION?

Ein anderes Problem ist, dass wenn ich roudn weglasse und mit einem real-
Wert rechne z.B. anstatt 13,65 dann 13,6499996185… rauskommt.
Vielleicht ist es auch irgendwie anders möglich zu sagen dass die Berechnung auf x Nachkommastelle erfolgen soll. Es sind sowieso höchstens 4 Nachkommastellen.

Viele Grüße

Wie in Mathe früher mal gelernt:

SELECT ROUND((42.232342::FLOAT * 100)) / 100;
 ?column?
----------
    42.23
(1 row)

Das ganze verlängert die Abfrage allerdings um ca. 100ms - außerdem werden die Nullen nicht mehr angezeigt falls es weniger als die vorgegebenen Nachkommastellen sind.

Du kannst auch hier weitere Parameter für ROUND() angeben, mein Beispiel sollte nur zeigen dass ROUND() nicht auf NUMERIC beschränkt ist.

Das *1 schaut auch komisch aus, warum verschwendest du da Rechenzeit für solche Operationen?

Aber egal.

Das *1 da ist Zufall.
Es gibt auch solche Formeln:
(((100/((x+0,24)*1,7)-4,341)/0,00676)/49)