Обсуждение: Plpgsql function with unknown number of args

Поиск
Список
Период
Сортировка

Plpgsql function with unknown number of args

От
"Relyea, Mike"
Дата:
I need to create my very first function.  I'm using 8.0.2 and I need a
function that I can call (from my client app) with an unknown number of
criteria for a select query.  The function will then return the results
of the query.  In my mind, it would go something like what I've outlined
below.  I realize that there are syntax mistakes etc, but this is just
an example:

CREATE TABLE mytable (
    a    INTEGER UNIQUE PRIMARY KEY,
    b    VARCHAR(100) NOT NULL,
);

CREATE FUNCTION myfunc(criteria) RETURNS ???? AS $$

BEGIN

    BEGIN
    FOREACH crit IN criteria
    critsql := "b = 'crit' OR "
    NEXT crit
    END;

    PERFORM "SELECT a, b FROM mytable WHERE (" critsql ");"

END;
$$ LANGUAGE plpgsql;


Select * from myfunc(1, 2, 3, 4) would then equate to SELECT a, b FROM
mytable WHERE (b = '1' OR b = '2' OR b = '3' OR b = '4');

Select * from myfunc(9, 21) would equate to SELECT a, b FROM mytable
WHERE (b = '9' OR b = '21');

My question is how do I do that?  I've looked through the docs and can't
find what I'm looking for.  I'm assuming this is possible because it's a
relatively simple task.

Mike

Re: Plpgsql function with unknown number of args

От
Harald Fuchs
Дата:
In article <1806D1F73FCB7F439F2C842EE0627B1801C32853@usa0300ms01.na.xerox.net>,
"Relyea, Mike" <Mike.Relyea@xerox.com> writes:

> I need to create my very first function.  I'm using 8.0.2 and I need a
> function that I can call (from my client app) with an unknown number of
> criteria for a select query.  The function will then return the results
> of the query.  In my mind, it would go something like what I've outlined
> below.  I realize that there are syntax mistakes etc, but this is just
> an example:

> CREATE TABLE mytable (
>     a    INTEGER UNIQUE PRIMARY KEY,
>     b    VARCHAR(100) NOT NULL,
> );

> CREATE FUNCTION myfunc(criteria) RETURNS ???? AS $$

> BEGIN

>     BEGIN
>     FOREACH crit IN criteria
>     critsql := "b = 'crit' OR "
>     NEXT crit
>     END;

>     PERFORM "SELECT a, b FROM mytable WHERE (" critsql ");"

> END;
> $$ LANGUAGE plpgsql;


> Select * from myfunc(1, 2, 3, 4) would then equate to SELECT a, b FROM
> mytable WHERE (b = '1' OR b = '2' OR b = '3' OR b = '4');

> Select * from myfunc(9, 21) would equate to SELECT a, b FROM mytable
> WHERE (b = '9' OR b = '21');

> My question is how do I do that?  I've looked through the docs and can't
> find what I'm looking for.  I'm assuming this is possible because it's a
> relatively simple task.

You can't have a variable number of args, but since all args have the
same type you can use an array.  The return type is a set of mytable
rows; thus myfunc becomes something like

  CREATE FUNCTION myfunc (TEXT[]) RETURNS SETOF mytable AS $$
    SELECT *
    FROM mytable
    WHERE b = ANY ($1)
  $$ LANGUAGE sql;

This function can be called like that:

  SELECT *
  FROM myfunc (ARRAY ['1', '2', '3', '4']);

  SELECT *
  FROM myfunc (ARRAY ['9', '21']);

Re: Plpgsql function with unknown number of args

От
Tony Caduto
Дата:
you coud pass in criteria as a delimted string, then
pull out each arg something like this


CREATE or REPLACE FUNCTION test_func( varchar)
RETURNS pg_catalog.void AS
$BODY$
DECLARE
IN_ARRAY text[] ;
arg1 varchar;
arg2 varchar;
arg3 varchar


begin
IN_ARRAY = string_to_array($1,'~^~');

arg1    = IN_ARRAY[1]
arg2    = IN_ARRAY[2]
arg3    = IN_ARRAY[3]

Then call the function like this:

select test_func('bla^~^bla~^~yada');

This example does not return anything, but you could build a select from the args you passed in then return a cursor.

normally PG is limited to 32 args (unless special compiled to support more), but with this technique you can pass in as
manyas you want. 

hope this helps.

Tony Caduto
AM Software Design
Home of PG Lightning Admin for Postgresql 8.x
http://www.amsoftwaredesign.com


> CREATE FUNCTION myfunc(criteria) RETURNS ???? AS $$
>
> BEGIN
>
>     BEGIN
>     FOREACH crit IN criteria
>     critsql := "b = 'crit' OR "
>     NEXT crit
>     END;
>
>     PERFORM "SELECT a, b FROM mytable WHERE (" critsql ");"
>
> END;
> $$ LANGUAGE plpgsql;
>

Re: Plpgsql function with unknown number of args

От
"Relyea, Mike"
Дата:
Thanks for the input.  This looks very promising.  I have one further
question.  My SQL statement is going to pull data from more than one
table in a relatively complex query.  How do I cast the RETURNS portion
of the function?  Again, I can't find what I'm looking for in the docs.
I've included an actual sample SQL statement.  I will only be changing
the first portion of the WHERE clause.

SELECT "PrintSamples"."MachineID", "PrintSamples"."PrintCopyID",
"tblColors"."Color", "tblBlockAC"."AreaCoverage",
"ParameterValues"."ParameterValue" AS "Mottle_NMF"
FROM ("AnalysisModules"
INNER JOIN ("tblColors"
INNER JOIN ("Targets"
INNER JOIN (("tblTPNamesAndColors"
INNER JOIN "PrintSamples"
    ON "tblTPNamesAndColors"."TestPatternName" =
"PrintSamples"."TestPatternName")
INNER JOIN (("DigitalImages"
INNER JOIN "PrintSampleAnalyses"
    ON "DigitalImages"."ImageID" = "PrintSampleAnalyses"."ImageID")
INNER JOIN ("ParameterNames"
INNER JOIN ("Measurements"
INNER JOIN "ParameterValues"
    ON "Measurements"."MeasurementID" =
"ParameterValues"."MeasurementID")
    ON "ParameterNames"."ParameterID" =
"ParameterValues"."ParameterID")
    ON "PrintSampleAnalyses"."psaID" = "Measurements"."psaID")
    ON "PrintSamples"."PrintSampleID" =
"DigitalImages"."PrintSampleID")
    ON "Targets"."TargetID" = "Measurements"."TargetID")
    ON "tblColors"."ColorID" = "tblTPNamesAndColors"."ColorID")
    ON "AnalysisModules"."MetricID" = "Measurements"."MetricID")
INNER JOIN "tblBlockAC"
    ON "Targets"."TargetID" = "tblBlockAC"."TargetID"
WHERE (("PrintSamples"."MachineID" = '2167' OR
"PrintSamples"."MachineID" = '2168' OR "PrintSamples"."MachineID" =
'2169')
AND (("tblBlockAC"."AreaCoverage")=100 Or
("tblBlockAC"."AreaCoverage")=60 Or ("tblBlockAC"."AreaCoverage")=40)
AND (("AnalysisModules"."AnalysisModuleName")='NMF')
AND (("ParameterNames"."ParameterName")='NMF'))
ORDER BY "PrintSamples"."MachineID", "PrintSamples"."PrintCopyID",
"tblColors"."ColorID";



-----Original Message-----
From: pgsql-general-owner@postgresql.org
[mailto:pgsql-general-owner@postgresql.org] On Behalf Of Harald Fuchs
Sent: Monday, April 18, 2005 3:49 PM
To: pgsql-general@postgresql.org
Subject: Re: [GENERAL] Plpgsql function with unknown number of args

In article
<1806D1F73FCB7F439F2C842EE0627B1801C32853@usa0300ms01.na.xerox.net>,
"Relyea, Mike" <Mike.Relyea@xerox.com> writes:

> I need to create my very first function.  I'm using 8.0.2 and I need a
> function that I can call (from my client app) with an unknown number
of
> criteria for a select query.  The function will then return the
results
> of the query.  In my mind, it would go something like what I've
outlined
> below.  I realize that there are syntax mistakes etc, but this is just
> an example:

> CREATE TABLE mytable (
>     a    INTEGER UNIQUE PRIMARY KEY,
>     b    VARCHAR(100) NOT NULL,
> );

> CREATE FUNCTION myfunc(criteria) RETURNS ???? AS $$

> BEGIN

>     BEGIN
>     FOREACH crit IN criteria
>     critsql := "b = 'crit' OR "
>     NEXT crit
>     END;

>     PERFORM "SELECT a, b FROM mytable WHERE (" critsql ");"

> END;
> $$ LANGUAGE plpgsql;


> Select * from myfunc(1, 2, 3, 4) would then equate to SELECT a, b FROM
> mytable WHERE (b = '1' OR b = '2' OR b = '3' OR b = '4');

> Select * from myfunc(9, 21) would equate to SELECT a, b FROM mytable
> WHERE (b = '9' OR b = '21');

> My question is how do I do that?  I've looked through the docs and
can't
> find what I'm looking for.  I'm assuming this is possible because it's
a
> relatively simple task.

You can't have a variable number of args, but since all args have the
same type you can use an array.  The return type is a set of mytable
rows; thus myfunc becomes something like

  CREATE FUNCTION myfunc (TEXT[]) RETURNS SETOF mytable AS $$
    SELECT *
    FROM mytable
    WHERE b = ANY ($1)
  $$ LANGUAGE sql;

This function can be called like that:

  SELECT *
  FROM myfunc (ARRAY ['1', '2', '3', '4']);

  SELECT *
  FROM myfunc (ARRAY ['9', '21']);


---------------------------(end of broadcast)---------------------------
TIP 3: if posting/reading through Usenet, please send an appropriate
      subscribe-nomail command to majordomo@postgresql.org so that your
      message can get through to the mailing list cleanly


Re: Plpgsql function with unknown number of args

От
Tom Lane
Дата:
"Relyea, Mike" <Mike.Relyea@xerox.com> writes:
> Thanks for the input.  This looks very promising.  I have one further
> question.  My SQL statement is going to pull data from more than one
> table in a relatively complex query.  How do I cast the RETURNS portion
> of the function?

In current releases, you'll have to create a named composite type that
matches what you want to return, and declare the function as returning
that type.

(PG 8.1 will have a facility for named OUT parameters that lets you
avoid the notational overhead of inventing a composite type, although
what happens under-the-hood is not really very different.)

            regards, tom lane

Re: Plpgsql function with unknown number of args

От
Tony Caduto
Дата:
You don't have to cast it as anything, just return a refcursor from your
function.

Say you return a refcursor called return_cursor

select myfunction(your_in_array);
fetch all from return_cursor;

If you are calling from a development environment, you put the return
value of the fuction (the refcursor name) into a variable, then
dynamicly build the fetch
all statement from return value of the function.  This must be done in
the context of a transaction, i.e. both statements must must be executed
in the same transaction.

The refcursors work really well and are very flexible.

Relyea, Mike wrote:

>Thanks for the input.  This looks very promising.  I have one further
>question.  My SQL statement is going to pull data from more than one
>table in a relatively complex query.  How do I cast the RETURNS portion
>of the function?  Again, I can't find what I'm looking for in the docs.
>I've included an actual sample SQL statement.  I will only be changing
>the first portion of the WHERE clause.
>
>