CASE und Aggregatfunktion

CASE und Aggregatfunktion

am 26.03.2009 10:18:01 von Marc Hanisch

Hallo Liste,

ich nutze öfter eine Query in ähnlicher Art und Weise:

SELECT name,
CASE WHEN SUM(betrag) > 0
THEN SUM(betrag)
ELSE 0
END AS einnahmen,
CASE WHEN SUM(betrag) < 0
THEN SUM(betrag)
ELSE 0
END AS ausgaben
FROM table
GROUP BY name

Erreichen will ich damit, dass ein und das selbe Feld in Abhängigkei=
t
des Inhaltes also unter anderem Namen (einnahmen und ausgaben) ausgeben
wird.
Es erscheint mir aber umständlich, dass ich PostgreSQL für die =
Bedingung
(WHEN) und für die Anweisung (THEN) um die Summierung bemühen m=
uss, was
ja wahrscheinlich doppelt Performance frisst... Gibt es da einen
eleganteren Weg? Schließlich wurde die Summe des Betrages ja bei der
ersten Bedingung bereits berechnet.

Viele Grüße,
Marc



--=20
Sent via pgsql-de-allgemein mailing list (pgsql-de-allgemein@postgresql.o=
rg)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-de-allgemein

Re: CASE und Aggregatfunktion

am 26.03.2009 11:05:43 von Thomas Markus

This is a multi-part message in MIME format.
--------------000604030505020402090906
Content-Type: text/plain; charset=UTF-8; format=flowed
Content-Transfer-Encoding: quoted-printable

Hi,

mach doch eher sowas wie:

SELECT name,
greatest(SUM(betrag),0) AS einnahmen,
least(SUM(betrag),0) AS ausgaben
FROM table
GROUP BY name


die abfrage scheint aber rein fachlich falsch zu sein da mindestens=20
einer der beiden summen 0 sein muss. Ich tippe mal es soll eher sowas=20
sein wie:

SELECT name,
sum(greatest(betrag,0)) AS einnahmen,
sum(least(betrag,0)) AS ausgaben
FROM table
GROUP BY 1


Gruss
Thomas


Marc Hanisch schrieb:
> Hallo Liste,
>
> ich nutze öfter eine Query in ähnlicher Art und Weise:
>
> SELECT name,
> CASE WHEN SUM(betrag) > 0
> THEN SUM(betrag)
> ELSE 0
> END AS einnahmen,
> CASE WHEN SUM(betrag) < 0
> THEN SUM(betrag)
> ELSE 0
> END AS ausgaben
> FROM table
> GROUP BY name
>
> Erreichen will ich damit, dass ein und das selbe Feld in Abhängigk=
eit
> des Inhaltes also unter anderem Namen (einnahmen und ausgaben) ausgeben
> wird.
> Es erscheint mir aber umständlich, dass ich PostgreSQL für di=
e Bedingung
> (WHEN) und für die Anweisung (THEN) um die Summierung bemühen=
muss, was
> ja wahrscheinlich doppelt Performance frisst... Gibt es da einen
> eleganteren Weg? Schließlich wurde die Summe des Betrages ja bei d=
er
> ersten Bedingung bereits berechnet.
>
> Viele Grüße,
> Marc
>
>
>
> =20

--=20
Thomas Markus

==================== =====3D=
==================== =====3D=
==
proventis GmbH | Zimmerstr. 79-81 | D-10117 Berlin |
Tel +49 (0)30 2936399-22 | Fax -50 | t.markus@proventis.net
------------------------------------------------------------ -----
Geschäftsführer: Norman Frischmuth | Sitz: Berlin
Handelsregister: AG Berlin-Charlottenburg, HR 82917
------------------------------------------------------------ -----
Blue Ant-webbasiertes Projektmanagement - aktuelle Termine 2008:
http://www.proventis.net/website/live/blueant/veranstaltunge n.html
==================== =====3D=
==================== =====3D=
==


--------------000604030505020402090906
Content-Type: text/x-vcard; charset=utf-8;
name="t_markus.vcf"
Content-Transfer-Encoding: base64
Content-Disposition: attachment;
filename="t_markus.vcf"

YmVnaW46dmNhcmQNCmZuOlRob21hcyBNYXJrdXMNCm46TWFya3VzO1Rob21h
cw0Kb3JnOnByb3ZlbnRpcyBHbWJIDQphZHI6OztaaW1tZXJzdHIuIDc5LTgw
O0JlcmxpbjtCZXJsaW47MTAxMTc7R2VybWFueQ0KZW1haWw7aW50ZXJuZXQ6
dC5tYXJrdXNAcHJvdmVudGlzLm5ldA0KdGVsO3dvcms6KzQ5IDMwIDI5IDM2
IDM5OSAyMg0KeC1tb3ppbGxhLWh0bWw6RkFMU0UNCnVybDpodHRwOi8vd3d3
LnByb3ZlbnRpcy5uZXQNCnZlcnNpb246Mi4xDQplbmQ6dmNhcmQNCg0K

--------------000604030505020402090906
Content-Type: text/plain
Content-Disposition: inline
MIME-Version: 1.0
Content-Transfer-Encoding: quoted-printable


--=20
Sent via pgsql-de-allgemein mailing list (pgsql-de-allgemein@postgresql.o=
rg)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-de-allgemein

--------------000604030505020402090906--

Re: CASE und Aggregatfunktion

am 26.03.2009 11:11:46 von Marc Hanisch

--- Original-Nachricht ---
Absender: Thomas Markus
Datum: 26.03.2009 11:05 Uhr
> Hi,
>
> mach doch eher sowas wie:
>
> SELECT name,
> greatest(SUM(betrag),0) AS einnahmen,
> least(SUM(betrag),0) AS ausgaben
> FROM table
> GROUP BY name
Hallo Thomas,

danke, es sollte nur ein etwas konstruiertes Beispiel sein (was im
übrigen so auch schon funktionierend im Einsatz ist). Es ging mehr e=
her
darum, ob ich einen Wert, den ich im CASE WHEN Ausdruck ermittle und
anschließend ausgeben möchte, nochmal ermitteln muss oder ob es=
, um
Performance zu sparen, eine elegantere Art und Weise gibt, ein CASE zu
formulieren. Anstelle der Aggregatfunktion hätte ich als Beispiel au=
ch
eine Subquery einfügen können, auch hier müsste die Subque=
ry zweimal
ausgeführt werden... Hoffe ich hab mich verständlich ausgedr=C3=
=BCckt ;-)

Viele Grüße,
Marc

--=20
Sent via pgsql-de-allgemein mailing list (pgsql-de-allgemein@postgresql.o=
rg)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-de-allgemein

Re: CASE und Aggregatfunktion

am 26.03.2009 11:29:45 von Andreas Kretschmer

Marc Hanisch wrote:

> Hallo Liste,
>=20
> ich nutze öfter eine Query in ähnlicher Art und Weise:
>=20
> SELECT name,
> CASE WHEN SUM(betrag) > 0
> THEN SUM(betrag)
> ELSE 0
> END AS einnahmen,
> CASE WHEN SUM(betrag) < 0
> THEN SUM(betrag)
> ELSE 0
> END AS ausgaben
> FROM table
> GROUP BY name

Bist Du Dir sicher, damit das zu erreichen, was Du willst?
Ich denke, Du willst eher

sum(
case when betrag > 0 then betrag else 0 end) as einnahmen,=20


> Es erscheint mir aber umständlich, dass ich PostgreSQL für die Bedi=
ngung
> (WHEN) und für die Anweisung (THEN) um die Summierung bemühen muss,=
was
> ja wahrscheinlich doppelt Performance frisst... Gibt es da einen
> eleganteren Weg? Schließlich wurde die Summe des Betrages ja bei der
> ersten Bedingung bereits berechnet.

Mir erscheint es unlogisch, was Du machst:

test=3D*# select * from summen;
i | s
---+------
1 | 10
2 | 20
3 | -5
4 | -100
(4 Zeilen)

Zeit: 0,218 ms
test=3D*# select case when sum(s) > 0 then sum(s) end as einnahmen, case =
when sum(s) < 0 then sum(s) end as ausgaben from summen;
einnahmen | ausgaben
-----------+----------
| -75
(1 Zeile)

Zeit: 0,274 ms
test=3D*# select sum(case when s > 0 then s else 0 end) as einnahmen, sum=
(case when s < 0 then s else 0 end) as ausgaben from summen;
einnahmen | ausgaben
-----------+----------
30 | -105
(1 Zeile)


Welche Variante willst Du?



Andreas
--=20
Really, I'm not out to destroy Microsoft. That will just be a completely
unintentional side effect. (Linus Torvalds)
"If I was god, I would recompile penguin with --enable-fly." (unknown)
Kaufbach, Saxony, Germany, Europe. N 51.05082°, E 13.56889=
°

--=20
Sent via pgsql-de-allgemein mailing list (pgsql-de-allgemein@postgresql.o=
rg)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-de-allgemein

Re: CASE und Aggregatfunktion

am 26.03.2009 11:54:41 von Marc Hanisch

--- Original-Nachricht ---
Absender: Andreas Kretschmer
Datum: 26.03.2009 11:29 Uhr
>
>
> Mir erscheint es unlogisch, was Du machst:
>
> test=3D*# select * from summen;
> i | s
> ---+------
> 1 | 10
> 2 | 20
> 3 | -5
> 4 | -100
> (4 Zeilen)
>
> Zeit: 0,218 ms
> test=3D*# select case when sum(s) > 0 then sum(s) end as einnahmen, cas=
e when sum(s) < 0 then sum(s) end as ausgaben from summen;
> einnahmen | ausgaben
> -----------+----------
> | -75
> (1 Zeile)
>
> Zeit: 0,274 ms
> test=3D*# select sum(case when s > 0 then s else 0 end) as einnahmen, s=
um(case when s < 0 then s else 0 end) as ausgaben from summen;
> einnahmen | ausgaben
> -----------+----------
> 30 | -105
> (1 Zeile)
>
>
> Welche Variante willst Du?
>
> =20
Hallo Andreas,

genau die erste Variante will ich! Vielleicht hab ich mein Beispiel
schlecht gewählt, mir ging es inhaltlich darum zu sehen, dass ich, w=
enn
ich z.B. eine Kasse verwalte, ich am Monatsende im Minus bin (also -75)
oder halt im Plus. War aber nur ein frei gewähltes Beispiel.
Inhaltlich geht es mir darum, dass der Part

sum(s)

nach dem WHEN angegeben wird, und wenn der Inhalt meinen Erwartungen
entspricht, ich ihn ja nochmal von Postgres berechnen lassen muss...
Toll wäre so was in der "Art" wie:

when a =3D sum(s) > 0 then a else 0

Mir ist schon klar, dass man Variablen nur mit einer benutzerdefinierten
Funktion und PLPSQL erreichen kann, aber ich hoffe es verdeutlicht, was
ich meine.

Viele Grüße und danke für eure Nerven ;-)
Marc


--=20
Sent via pgsql-de-allgemein mailing list (pgsql-de-allgemein@postgresql.o=
rg)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-de-allgemein

Re: CASE und Aggregatfunktion

am 26.03.2009 11:56:05 von Marc Hanisch

--- Original-Nachricht ---
Absender: Andreas Kretschmer
Datum: 26.03.2009 11:29 Uhr
>
>
> Mir erscheint es unlogisch, was Du machst:
>
> test=3D*# select * from summen;
> i | s
> ---+------
> 1 | 10
> 2 | 20
> 3 | -5
> 4 | -100
> (4 Zeilen)
>
> Zeit: 0,218 ms
> test=3D*# select case when sum(s) > 0 then sum(s) end as einnahmen, cas=
e when sum(s) < 0 then sum(s) end as ausgaben from summen;
> einnahmen | ausgaben
> -----------+----------
> | -75
> (1 Zeile)
>
> Zeit: 0,274 ms
> test=3D*# select sum(case when s > 0 then s else 0 end) as einnahmen, s=
um(case when s < 0 then s else 0 end) as ausgaben from summen;
> einnahmen | ausgaben
> -----------+----------
> 30 | -105
> (1 Zeile)
>
>
> Welche Variante willst Du?
>
> =20
Hallo Andreas,

genau die erste Variante will ich! Vielleicht hab ich mein Beispiel
schlecht gewählt, mir ging es inhaltlich darum zu sehen, dass ich, w=
enn
ich z.B. eine Kasse verwalte, ich am Monatsende im Minus bin (also -75)
oder halt im Plus. War aber nur ein frei gewähltes Beispiel.
Inhaltlich geht es mir darum, dass der Part

sum(s)

nach dem WHEN angegeben wird, und wenn der Inhalt meinen Erwartungen
entspricht, ich ihn ja nochmal von Postgres berechnen lassen muss...
Toll wäre so was in der "Art" wie:

when a =3D sum(s) > 0 then a else 0

Mir ist schon klar, dass man Variablen nur mit einer benutzerdefinierten
Funktion und PLPSQL erreichen kann, aber ich hoffe es verdeutlicht, was
ich meine.

Viele Grüße und danke für eure Nerven ;-)
Marc



--=20
Sent via pgsql-de-allgemein mailing list (pgsql-de-allgemein@postgresql.o=
rg)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-de-allgemein

Re: CASE und Aggregatfunktion

am 26.03.2009 12:52:52 von Andreas Kretschmer

Marc Hanisch wrote:

> Hallo Liste,
>=20
> ich nutze öfter eine Query in ähnlicher Art und Weise:
>=20
> SELECT name,
> CASE WHEN SUM(betrag) > 0
> THEN SUM(betrag)
> ELSE 0
> END AS einnahmen,
> CASE WHEN SUM(betrag) < 0
> THEN SUM(betrag)
> ELSE 0
> END AS ausgaben
> FROM table
> GROUP BY name
>=20
> Erreichen will ich damit, dass ein und das selbe Feld in Abhängigkeit
> des Inhaltes also unter anderem Namen (einnahmen und ausgaben) ausgeben
> wird.
> Es erscheint mir aber umständlich, dass ich PostgreSQL für die Bedi=
ngung
> (WHEN) und für die Anweisung (THEN) um die Summierung bemühen muss,=
was
> ja wahrscheinlich doppelt Performance frisst... Gibt es da einen
> eleganteren Weg? Schließlich wurde die Summe des Betrages ja bei der
> ersten Bedingung bereits berechnet.

Okay, ich kann Dich beruhigen.

Ich erzeuge mir mal eine saudumme Aggregatfunktion, die eigentlich nix
weiter macht, als 1 zu liefern. Saudumm also. Nebenbei plappert sie aber
auch noch rum, immer wenn sie aufgrufen wird. Nicht so dumm für uns,
weil man dann sieht, wie oft sie aufgerufen wird:

test=3D# select * from summen;
i | s
---+------
1 | 10
2 | 20
3 | -5
4 | -100
(4 Zeilen)

Zeit: 0,151 ms
test=3D*# create or replace function agg_test(int, int) returns int as $$=
begin raise notice 'bin hier %',$2; return 1; end; $$language plpgsql imm=
utable strict;
CREATE FUNCTION
Zeit: 0,695 ms
test=3D*# create aggregate agg_test(basetype=3Dint, sfunc=3Dagg_test, sty=
pe=3Dint,initcond=3D1);
CREATE AGGREGATE
Zeit: 0,507 ms
test=3D*# select case when agg_test(s) > 0 then agg_test(s) end as einnah=
men, case when agg_test(s) < 0 then agg_test(s) end as ausgaben from summ=
en;
NOTICE: bin hier 10
NOTICE: bin hier 20
NOTICE: bin hier -5
NOTICE: bin hier -100
einnahmen | ausgaben
-----------+----------
1 |
(1 Zeile)


Wie man sieht, wird sie nur 1 mal pro Zeile aufgerufen. PG ist als
schlau genug, das zu optimieren.



Andreas
--=20
Really, I'm not out to destroy Microsoft. That will just be a completely
unintentional side effect. (Linus Torvalds)
"If I was god, I would recompile penguin with --enable-fly." (unknown)
Kaufbach, Saxony, Germany, Europe. N 51.05082°, E 13.56889=
°

--=20
Sent via pgsql-de-allgemein mailing list (pgsql-de-allgemein@postgresql.o=
rg)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-de-allgemein

Re: CASE und Aggregatfunktion

am 26.03.2009 13:04:40 von Marc Hanisch

--- Original-Nachricht ---
Absender: Andreas Kretschmer
Datum: 26.03.2009 12:52 Uhr
> Okay, ich kann Dich beruhigen.
>
> Ich erzeuge mir mal eine saudumme Aggregatfunktion, die eigentlich nix
> weiter macht, als 1 zu liefern. Saudumm also. Nebenbei plappert sie abe=
r
> auch noch rum, immer wenn sie aufgrufen wird. Nicht so dumm für un=
s,
> weil man dann sieht, wie oft sie aufgerufen wird:
>
> test=3D# select * from summen;
> i | s
> ---+------
> 1 | 10
> 2 | 20
> 3 | -5
> 4 | -100
> (4 Zeilen)
>
> Zeit: 0,151 ms
> test=3D*# create or replace function agg_test(int, int) returns int as =
$$begin raise notice 'bin hier %',$2; return 1; end; $$language plpgsql i=
mmutable strict;
> CREATE FUNCTION
> Zeit: 0,695 ms
> test=3D*# create aggregate agg_test(basetype=3Dint, sfunc=3Dagg_test, s=
type=3Dint,initcond=3D1);
> CREATE AGGREGATE
> Zeit: 0,507 ms
> test=3D*# select case when agg_test(s) > 0 then agg_test(s) end as einn=
ahmen, case when agg_test(s) < 0 then agg_test(s) end as ausgaben from su=
mmen;
> NOTICE: bin hier 10
> NOTICE: bin hier 20
> NOTICE: bin hier -5
> NOTICE: bin hier -100
> einnahmen | ausgaben
> -----------+----------
> 1 |
> (1 Zeile)
>
>
> Wie man sieht, wird sie nur 1 mal pro Zeile aufgerufen. PG ist als
> schlau genug, das zu optimieren.
>
> =20
Hallo Andreas,

vielen Dank! Ich bin beeindruckt :-)
Jetzt bin ich beruhigt, da meine Query vielleicht blöd aussieht,
Postgres aber schlau genug dafür ist...

Viele Grüße,
Marc

--=20
Sent via pgsql-de-allgemein mailing list (pgsql-de-allgemein@postgresql.o=
rg)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-de-allgemein

Re: CASE und Aggregatfunktion

am 26.03.2009 14:00:47 von Albe Laurenz

TWFyYyBIYW5pc2NoIHdyb3RlOg0KPiBpY2ggbnV0emUgw7ZmdGVyIGVpbmUg
UXVlcnkgaW4gw6RobmxpY2hlciBBcnQgdW5kIFdlaXNlOg0KPiANCj4gU0VM
RUNUIG5hbWUsDQo+ICAgICAgICBDQVNFIFdIRU4gU1VNKGJldHJhZykgPiAw
DQo+ICAgICAgICAgICAgIFRIRU4gU1VNKGJldHJhZykNCj4gICAgICAgICAg
ICAgRUxTRSAwDQo+ICAgICAgICBFTkQgQVMgZWlubmFobWVuLA0KPiAgICAg
ICAgQ0FTRSBXSEVOIFNVTShiZXRyYWcpIDwgMA0KPiAgICAgICAgICAgICBU
SEVOIFNVTShiZXRyYWcpDQo+ICAgICAgICAgICAgIEVMU0UgMA0KPiAgICAg
ICAgRU5EIEFTIGF1c2dhYmVuDQo+IEZST00gICB0YWJsZQ0KPiBHUk9VUCBC
WSBuYW1lDQo+IA0KPiBFcnJlaWNoZW4gd2lsbCBpY2ggZGFtaXQsIGRhc3Mg
ZWluIHVuZCBkYXMgc2VsYmUgRmVsZCBpbiBBYmjDpG5naWdrZWl0DQo+IGRl
cyBJbmhhbHRlcyBhbHNvIHVudGVyIGFuZGVyZW0gTmFtZW4gKGVpbm5haG1l
biB1bmQgYXVzZ2FiZW4pIGF1c2dlYmVuDQo+IHdpcmQuDQo+IEVzIGVyc2No
ZWludCBtaXIgYWJlciB1bXN0w6RuZGxpY2gsIGRhc3MgaWNoIFBvc3RncmVT
UUwgZsO8ciBkaWUgQmVkaW5ndW5nDQo+IChXSEVOKSB1bmQgZsO8ciBkaWUg
QW53ZWlzdW5nIChUSEVOKSB1bSBkaWUgU3VtbWllcnVuZyBiZW3DvGhlbiBt
dXNzLCB3YXMNCj4gamEgd2FocnNjaGVpbmxpY2ggZG9wcGVsdCBQZXJmb3Jt
YW5jZSBmcmlzc3QuLi4gR2lidCBlcyBkYSBlaW5lbg0KPiBlbGVnYW50ZXJl
biBXZWc/IFNjaGxpZcOfbGljaCB3dXJkZSBkaWUgU3VtbWUgZGVzIEJldHJh
Z2VzIGphIGJlaSBkZXINCj4gZXJzdGVuIEJlZGluZ3VuZyBiZXJlaXRzIGJl
cmVjaG5ldC4NCg0KSWNoIG11w58genVlcnN0IGVpbm1hbCBzYWdlbiwgaWNo
IGJpbiBuaWNodCBzaWNoZXIsIG9iIFBvc3RncmVTUUwgaW4gZGllc2VtDQpG
YWxsIGRpZSBTdW1tZSB3aXJrbGljaCBtZWhybWFscyBiZXJlY2huZXQgLSBk
YSBrYW5uIHZpZWxsZWljaHQgd2VyDQpCZXJ1ZmVuZXJlciBBdXNrdW5mdCBn
ZWJlbi4NCg0KSWNoIGjDpHR0ZSBkaWUgQWJmcmFnZSBzbyBmb3JtdWxpZXJ0
Og0KDQpTRUxFQ1QgbmFtZSwNCiAgICAgICBDQVNFIFdIRU4gc3VtX2JldHJh
ZykgPiAwDQogICAgICAgICAgICBUSEVOIHN1bV9iZXRyYWcpDQogICAgICAg
ICAgICBFTFNFIDANCiAgICAgICBFTkQgQVMgZWlubmFobWVuLA0KICAgICAg
IENBU0UgV0hFTiBzdW1fYmV0cmFnKSA8IDANCiAgICAgICAgICAgIFRIRU4g
c3VtX2JldHJhZykNCiAgICAgICAgICAgIEVMU0UgMA0KICAgICAgIEVORCBB
UyBhdXNnYWJlbg0KRlJPTSAgIChTRUxFQ1QgbmFtZSwgc3VtKGJldHJhZykg
QVMgc3VtX2JldHJhZw0KICAgICAgICBGUk9NIHRhYmxlDQogICAgICAgIEdS
T1VQIEJZIG5hbWUpIGR1bW15Ow0KDQpMaWViZSBHcsO8w59lLA0KTGF1cmVu
eiBBbGJlDQoKLS0gClNlbnQgdmlhIHBnc3FsLWRlLWFsbGdlbWVpbiBtYWls
aW5nIGxpc3QgKHBnc3FsLWRlLWFsbGdlbWVpbkBwb3N0Z3Jlc3FsLm9yZykK
VG8gbWFrZSBjaGFuZ2VzIHRvIHlvdXIgc3Vic2NyaXB0aW9uOgpodHRwOi8v
d3d3LnBvc3RncmVzcWwub3JnL21haWxwcmVmL3Bnc3FsLWRlLWFsbGdlbWVp
bgo=