2012-02-11 90 views
1

我经常在postgresql中使用复制函数,我想我会创建一个函数来使用它。 所以我们可以说我下表如何将参数传递给函数中的pgsql命令?

create table users 
(
    userid serial primary key, 
    prefix varchar(10) not null, 
    firstname varchar(255) not null, 
    lastname varchar(255) not null, 
    email varchar(500) not null, 
    password varchar(255) not null, 
    created timestamp not null, 
    modified timestamp not null 
); 

与下面的函数具有

create function getUsersCSV() 
RETURNS void AS 
$BODY$ 
    BEGIN 
    COPY (select * from users) 
    TO 'c:\temp\users.csv' 
    WITH HEADER 
    CSV QUOTE '"' DELIMITER ','; 
    END 
$BODY$ 
LANGUAGE PLPGSQL; 

功能的作品,但如果我改变功能

create function getUsersCSV(filepath varchar) 
RETURNS void AS 
$BODY$ 
    BEGIN 
    COPY (select * from users) 
    TO filepath 
    WITH HEADER 
    CSV QUOTE '"' DELIMITER ','; 
    END 
$BODY$ 
LANGUAGE PLPGSQL; 

它抛出下面的语法错误 错误:在“filepath”处或附近的语法错误 SQL状态:42601

无论如何要参数化复制命令的目标值吗?

+0

您使用的是哪个版本的PostgreSQL? – 2012-02-11 08:19:55

+0

[plpgsql:连接变量到FROM子句]的可能重复(http://stackoverflow.com/questions/6258345/plpgsql-concatenation-of-variable-into-from-clause) – 2012-02-11 08:24:33

回答

2

您可以用execute做到这一点:

create function get_users_csv(filepath text) returns void as $$ 
declare 
    cp_cmd text; 
begin 
    cp_cmd := 'copy (select * from users) to ' 
      || quote_literal(filepath) 
      || ' with header csv quote ''"'' delimiter '','''; 
    execute cp_cmd; 
end; 
$$ language plpgsql; 

不要忘了,以防万一您filepath使用quote_literal。你也可以使用美元报价,如果你不喜欢所有的一倍,单引号:

create function get_users_csv(filepath text) returns void as $$ 
declare 
    cp_cmd text; 
begin 
    cp_cmd := $q$copy (select * from users) to $q$ 
      || quote_literal(filepath) 
      || $q$ with header csv quote '"' delimiter ','$q$; 
    execute cp_cmd; 
end; 
$$ language plpgsql; 

但我发现美元报价是相当难看比文本块的任何其他。

+0

对于美元引用+1,这是一个祝福,如果你需要在一个字符串中包含单引号。 (所以,不需要查询字符串的第一部分。)简化'(从用户中选择*)到'用户'。 – 2012-02-11 14:59:05

+1

在这种情况下,您必须是超级用户,因此您必须使用安全定义函数。有必要检查路径,因为没有精确的检查,有人可能会破坏你的数据 – 2012-02-11 15:23:01

相关问题