问题
I am trying to call a function within a function using sql on postgres 9.3.
This question is related to another post by me.
I have written the below function. So far I have failed to incorporate any kind of save-output (COPY) statement, so I am trying to work around this by creating a nested function print-out function.
CREATE FUNCTION retrieve_info(TEXT, TEXT) RETURNS SETOF
retrieve_info_tbl AS $$
SELECT tblA.id, tblA.method, tblA.species, tblA.location
FROM tblA
WHERE method=$1 AND species=$2
GROUP BY id, method, species
ORDER BY location
$$ LANGUAGE 'sql';
The above function works.
An attempt to create a nested function.
CREATE FUNCTION print_out(TEXT, TEXT) RETURNS void AS $$
COPY (SELECT * FROM retrieve_info($1, $2)) TO 'myfilepath/test.csv'
WITH CSV HEADER;
$$ LANGUAGE 'sql';
Calling nested function.
SELECT * FROM print_out('mtd1','sp1');
OUTPUT
The above gives this ERROR: column "$1" does not exist SQL state: 42P02 Context: SQL function "print_out" statement 1
. However, when substituting the arg1, arg2 in print_out() with 'mtd1','sp1' the correct output is printed to test.csv (as seen below)
id | method | ind | location
----------------------------
1a | mtd1 | sp3 | locA
1d | mtd1 | sp3 | locB
How would I get the arg1, arg2 of retrieve_info() to call arg1, arg2 properly within print_out()?
I am completely stuck. Would appreciate any pointers, thanks
回答1:
COPY is a bit odd as it sort of treats its query
argument as a string even though it isn't written as a string. The result is that the query
:
SELECT * FROM retrieve_info($1, $2)
isn't executed in the context of the function, it is executed in the context of COPY itself. Even though you say:
copy (select * from t) ...
it is treated more as though you wrote:
copy 'select * from t' ...
so by the time the query is executed, the function parameters no longer have any meaning, the query
argument to COPY may look like it would behave like a closure in other languages but it doesn't, it acts more like a string that gets passed to eval
.
You can get around this strangeness by using the usual Kludge of Last Resort: dynamic SQL. You should get better results if you write your function to use string wrangling and EXECUTE:
create or replace function print_out(text, text) returns void as $$
begin
execute 'copy ('
|| 'select * from retrieve_info'
|| '(' || quote_literal($1) || ',' || quote_literal($2) || ')'
|| ') to ''myfilepath/test.csv'' with csv header;';
end;
$$ language plpgsql;
回答2:
Are x
and y
quoted intentionally?
COPY (SELECT * FROM retrieve_info('x','y')) TO 'myfilepath/test.csv'
You are not sending the x
and y
arguments of print_out
to retrieve_info
- rather, you are sending the strings 'x'
and 'y'
. Assuming you don't have records with method='x' AND species='y'
, it's of little wonder you get no results.
Try this instead:
COPY (SELECT * FROM retrieve_info(x,y)) TO 'myfilepath/test.csv'
来源:https://stackoverflow.com/questions/19918385/calling-a-stored-procedure-within-a-stored-procedure