Re: Aggregate functions with two or more arguments?

From: Mike Mascari <mascarm(at)mascari(dot)com>
To: Brian K Boonstra <postgresql(at)boonstra(dot)org>
Cc: pgsql-general(at)postgresql(dot)org
Subject: Re: Aggregate functions with two or more arguments?
Date: 2004-07-15 05:13:07
Message-ID: 40F61263.7020805@mascari.com
Views: Raw Message | Whole Thread | Download mbox | Resend email
Thread:
Lists: pgsql-general

Brian K Boonstra wrote:

> Let's say that I want to efficiently compute something like a weighted
> standard deviation (the actual formula I have in mind is slightly more
> complicated). The kind of SQL statement I want to have work is
> something like
>
> SELECT weighted_stdev( t.val, t.weight ) FROM target_vals_tbl t
> WHERE t.val > 0;
>
>
> I thought I'd like to write a C function (or more properly a set of two
> C functions) into the server side to handle this, and then declare it as
> an aggregate using CREATE AGGREGATE. However, aggregate functions
> appear to want just a single argument, so I feel like either I am on the
> wrong track, or I have run into a limitation of postgresql.

I'm not sure what the most elegant solution is, but when I've
encountered this scenario in the past, I created a custom type for
the aggregate. So this meant creating an input and output function
for the type, and then creating a function to return the type for
use in the aggregate. Example:

CREATE OR REPLACE FUNCTION tier_input(cstring) RETURNS tier
AS '/usr/local/pgsql/lib/tradedb.so'
LANGUAGE 'C' WITH (isStrict);

CREATE OR REPLACE FUNCTION tier_output(tier) RETURNS cstring
AS '/usr/local/pgsql/lib/tradedb.so'
LANGUAGE 'C' WITH (isStrict);

CREATE TYPE tier (
INTERNALLENGTH = 136,
INPUT = tier_input,
OUTPUT = tier_output
);

CREATE OR REPLACE FUNCTION to_tier(text, text, text, int4, int4)
RETURNS tier
AS '/usr/local/pgsql/lib/tradedb.so'
LANGUAGE 'C' WITH (isStrict);

CREATE OR REPLACE FUNCTION the_amount(tier) RETURNS text
AS '/usr/local/pgsql/lib/tradedb.so'
LANGUAGE 'C' WITH (isStrict);

CREATE OR REPLACE FUNCTION tier_s(tier, tier) RETURNS tier
AS '/usr/local/pgsql/lib/tradedb.so'
LANGUAGE 'C' WITH (isStrict);

CREATE OR REPLACE FUNCTION tier_f(tier) RETURNS tier
AS '/usr/local/pgsql/lib/tradedb.so'
LANGUAGE 'C' WITH (isStrict);

CREATE AGGREGATE tier_sum (
BASETYPE = tier,
SFUNC = tier_s,
STYPE = tier,
FINALFUNC = tier_f,
INITCOND = '0 0 temp_table 0 0'
);

And then I invoke the aggregate like:

SELECT tier_sum(to_tier(a, b, c, d, e))
FROM foo
WHERE bar;

HTH,

Mike Mascari

In response to

Responses

Browse pgsql-general by date

  From Date Subject
Next Message javier wilson 2004-07-15 07:49:31 tcl and rpms for rhel3
Previous Message Robert Treat 2004-07-15 05:06:34 Re: determining supported timezones