Обсуждение: Table name as parameter in function

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

Table name as parameter in function

От
Alexander Pucher
Дата:
Hi,

struggling around with this for some time:

How can I use a table name as a parameter in a PL/pgSQL function ??

I tried this but it didn't work...


CREATE OR REPLACE FUNCTION my_row_count(text) RETURNS int4 AS '
DECLARE
    num_rows int4;
BEGIN
    num_rows := (select count(*) from $1);
    RETURN num_rows;
END;
' LANGUAGE plpgsql;

Thnaks for any input!

regards,
alex.

Re: Table name as parameter in function

От
Timothy Perrigo
Дата:
You'll need to use the EXECUTE command to build the SQL dynamically.

See:
http://www.postgresql.org/docs/7.4/interactive/plpgsql-
statements.html#PLPGSQL-STATEMENTS-EXECUTING-DYN

On Nov 23, 2004, at 2:56 PM, Alexander Pucher wrote:

> Hi,
>
> struggling around with this for some time:
>
> How can I use a table name as a parameter in a PL/pgSQL function ??
>
> I tried this but it didn't work...
>
>
> CREATE OR REPLACE FUNCTION my_row_count(text) RETURNS int4 AS '
> DECLARE
>    num_rows int4;
> BEGIN
>    num_rows := (select count(*) from $1);
>    RETURN num_rows;
> END;
> ' LANGUAGE plpgsql;
>
> Thnaks for any input!
>
> regards,
> alex.
>
> ---------------------------(end of
> broadcast)---------------------------
> TIP 1: subscribe and unsubscribe commands go to
> majordomo@postgresql.org
>


Re: Table name as parameter in function

От
Alexander Pucher
Дата:
Tim,

I'm afraid, I didn't get the point. Could you give me an example code
snippet of how to use the EXECUTE command in my case. Do I have to use
the EXECUTE within my function?

Thanks a lot,
alex.

Timothy Perrigo wrote:

> You'll need to use the EXECUTE command to build the SQL dynamically.
>
> See:
> http://www.postgresql.org/docs/7.4/interactive/plpgsql-
> statements.html#PLPGSQL-STATEMENTS-EXECUTING-DYN
>
> On Nov 23, 2004, at 2:56 PM, Alexander Pucher wrote:
>
>> Hi,
>>
>> struggling around with this for some time:
>>
>> How can I use a table name as a parameter in a PL/pgSQL function ??
>>
>> I tried this but it didn't work...
>>
>>
>> CREATE OR REPLACE FUNCTION my_row_count(text) RETURNS int4 AS '
>> DECLARE
>>    num_rows int4;
>> BEGIN
>>    num_rows := (select count(*) from $1);
>>    RETURN num_rows;
>> END;
>> ' LANGUAGE plpgsql;
>>
>> Thnaks for any input!
>>
>> regards,
>> alex.
>>
>> ---------------------------(end of
>> broadcast)---------------------------
>> TIP 1: subscribe and unsubscribe commands go to
>> majordomo@postgresql.org
>>
>
>
> ---------------------------(end of broadcast)---------------------------
> TIP 6: Have you searched our list archives?
>
>               http://archives.postgresql.org
>
>

--
--------------------------------------------------------
Departement of Geography and Regional Research
University of Vienna
Cartography and GIS
--------------------------------------------------------
Virtual Map Forum: http://www.gis.univie.ac.at/vmf
--------------------------------------------------------


Re: Table name as parameter in function

От
Timothy Perrigo
Дата:
Sorry for the brief response earlier; I was a bit rushed.  After
looking into it, it's a bit messier than I thought (at least, as far as
I can tell...perhaps one of the gurus on this list can show us a better
way).

Ordinarily, when you write select statements (for example) in a plpgsql
function, it will attempt to cache the execution plan.  In your case,
though, you want to be able to hit different tables each time your
function is invoked, so you need a way to construct and execute your
query dynamically.  That's where the EXECUTE statement comes in.
EXECUTE allows you to issue a command that is prepared every time it is
run.

In your case, though, things are a bit trickier.  There's no way to get
the results of a dynamically executed select statement within a plpgsql
function (according to the docs, the results are discarded).  In your
example, you need to be able to run a dynamic sql statement and get a
result back.

I thought a temp table might work in this situation, so I tried
something like this (using PostgreSQL 8.0 beta 4):

create or replace function count_rows(table_name text) returns integer
as
$$
declare c integer;
begin
       execute 'select count(*) into temp count_tbl from ' ||
quote_ident(table_name);
         select count into c from count_tbl;
         return c;
end;
$$
language 'plpgsql';

Unfortunately, you can't use EXECUTE to do a SELECT INTO.  So, as if
that wasn't ugly enough, I ended up having to do the following:

create or replace function count_rows(table_name text) returns integer
as
$$
declare c integer;
begin
         execute 'create temp table count_tbl(count integer)';
         execute 'insert into count_tbl(count) select count(*) from ' ||
quote_ident(table_name);
         select count into c from count_tbl;
         return c;
end;
$$
language 'plpgsql';

That works, but it is definitely not very pretty (if you use it, you'll
probably want to also add some code to drop the temp table...if you
search through the recent messages on this list, there's question I
asked about adding such a cleanup mechanism to a function that may be
helpful).

If anyone knows a cleaner way to solve Alexander's problem, I'd be
really interested to hear it!

Hope this helps,
Tim


On Nov 23, 2004, at 5:32 PM, Alexander Pucher wrote:

> Tim,
>
> I'm afraid, I didn't get the point. Could you give me an example code
> snippet of how to use the EXECUTE command in my case. Do I have to use
> the EXECUTE within my function?
>
> Thanks a lot,
> alex.
>
> Timothy Perrigo wrote:
>
>> You'll need to use the EXECUTE command to build the SQL dynamically.
>>
>> See:
>> http://www.postgresql.org/docs/7.4/interactive/plpgsql-
>> statements.html#PLPGSQL-STATEMENTS-EXECUTING-DYN
>>
>> On Nov 23, 2004, at 2:56 PM, Alexander Pucher wrote:
>>
>>> Hi,
>>>
>>> struggling around with this for some time:
>>>
>>> How can I use a table name as a parameter in a PL/pgSQL function ??
>>>
>>> I tried this but it didn't work...
>>>
>>>
>>> CREATE OR REPLACE FUNCTION my_row_count(text) RETURNS int4 AS '
>>> DECLARE
>>>    num_rows int4;
>>> BEGIN
>>>    num_rows := (select count(*) from $1);
>>>    RETURN num_rows;
>>> END;
>>> ' LANGUAGE plpgsql;
>>>
>>> Thnaks for any input!
>>>
>>> regards,
>>> alex.
>>>
>>> ---------------------------(end of
>>> broadcast)---------------------------
>>> TIP 1: subscribe and unsubscribe commands go to
>>> majordomo@postgresql.org
>>>
>>
>>
>> ---------------------------(end of
>> broadcast)---------------------------
>> TIP 6: Have you searched our list archives?
>>
>>               http://archives.postgresql.org
>>
>>
>
> --
> -------------------------------------------------------- Departement
> of Geography and Regional Research
> University of Vienna
> Cartography and GIS
> --------------------------------------------------------
> Virtual Map Forum: http://www.gis.univie.ac.at/vmf
> --------------------------------------------------------
>
> ---------------------------(end of
> broadcast)---------------------------
> TIP 5: Have you checked our extensive FAQ?
>
>               http://www.postgresql.org/docs/faqs/FAQ.html
>


Re: Table name as parameter in function

От
Stephan Szabo
Дата:
On Tue, 23 Nov 2004, Timothy Perrigo wrote:

> Sorry for the brief response earlier; I was a bit rushed.  After
> looking into it, it's a bit messier than I thought (at least, as far as
> I can tell...perhaps one of the gurus on this list can show us a better
> way).
>
> Ordinarily, when you write select statements (for example) in a plpgsql
> function, it will attempt to cache the execution plan.  In your case,
> though, you want to be able to hit different tables each time your
> function is invoked, so you need a way to construct and execute your
> query dynamically.  That's where the EXECUTE statement comes in.
> EXECUTE allows you to issue a command that is prepared every time it is
> run.
>
> In your case, though, things are a bit trickier.  There's no way to get
> the results of a dynamically executed select statement within a plpgsql
> function (according to the docs, the results are discarded).  In your

Explain as a statement doesn't return results, but FOR recordvar IN
EXECUTE ... should work.  It's still ugly, but something like

create or replace function count_rows(table_name text) returns integer
as
$$
declare
 foo record;
begin
 for foo in execute 'select count(*) as count from ' || quote_ident($1)
loop
  return foo.count;
 end loop;
end;
$$ language 'plpgsql';

should work for 8.0b. IIRC, at least 7.4 should work similarly if you
change the quoting.