3

我可能在这里扭曲了 postgres,但从根本上说,我想做的是获取一个字符串变量并将其传递给仅使用 psql 的 sql 命令(在本例中为 COPY)。

所以这就是我想出的。这些命令被分成 2 个文件,因为我希望能够在其他情况下使用 mydb_functions:

文件一:mydb_functions--1.0.sql (在共享/扩展和 mydb_functions.control 中也按照手册中的描述进行设置。给定文件名,返回完整的文件路径。这样做只是为了在下面的 add_data.sql 中制作 COPY 语句,更整洁。

CREATE OR REPLACE FUNCTION fpn(filename text) RETURNS TEXT as '
  DECLARE 
    mypath text := ''/path/to/my/directory/'';
  BEGIN
    RETURN mypath || filename;
  END
' LANGUAGE plpgsql;

文件二: add_data.sql 。这仅用于在命令行使用 psql 将数据复制到现有的 postgres 表中。注意:由于 CREATE EXTENSION 命令,需要以超级用户权限运行 psql。

CREATE EXTENSION IF NOT EXISTS mydb_functions;
-- haven't figured out how to create a function without arguments yet.
CREATE OR REPLACE FUNCTION test (dummyvar text) RETURNS text as '     
  DECLARE 
    filepath RECORD;
  BEGIN 
    SELECT * INTO filepath from fpn(''mydatafile.data'');
    COPY tablename (columnname) FROM filepath;
  END
' LANGUAGE plpgsql;

我坚持的部分是如何从文件路径记录中提取文本以在 COPY 命令中使用。也欢迎任何有关实现此目标的更简单方法的提示。我认为创建一个表来存储变量比这容易得多。但我想完成最后一步。

4

1 回答 1

0

如果您的问题COPY使用动态目标路径运行,EXECUTE请用于运行formatted SQL 查询。

CREATE OR REPLACE FUNCTION test () RETURNS text as $$ 
  DECLARE 
    filepath RECORD;
  BEGIN 
    SELECT * INTO filepath from fpn('mydatafile.data');
    EXECUTE format('COPY tablename (columnname) FROM %L', filepath);
  END
$$ LANGUAGE plpgsql;

看,这失败了:

DO
$$
DECLARE
    somevar text;
BEGIN
    somevar := '/tmp/somepath.csv';
    COPY tablename(columnname) FROM somevar;
END;
$$;

但这有效:

DO
$$
DECLARE
    somevar text;
BEGIN
    somevar := '/tmp/somepath.csv';
    EXECUTE format('COPY tablename(columnname) FROM %L', somevar);
END;
$$;

看:

format()%L说明符自动引用文字。%I对标识符做同样的事情。


如果正如我最初所想的那样,您正在谈论psql从外部获取数据,您可能会发现psql变量和变量插值很有用:

$ psql -v filepath=/path/to/my/directory/mydatafile.data regress
regress=> SELECT :'filepath';
               ?column?                
---------------------------------------
 /path/to/my/directory/mydatafile.data
(1 row)

注意冒号不加引号,然后变量名加引号。奇怪的语法,我知道。这仅适用于psql; 它在(比如)PgAdmin-III 中不起作用。

或者,您可以使用 here-document(特定于类 unix 的 shell,在 Windows' 中不起作用cmd.exe)来进行引用文本插值:

$ FILEPATH=/path/to/my/directory/mydatafile.data
$ psql regress <<__END__
SELECT '$FILEPATH';
__END__

               ?column?                
---------------------------------------
 /path/to/my/directory/mydatafile.data
(1 row)

这两个都展示了如何将一个变量从 shell 级别插入到psql. 从那里开始,在你的函数中使用它是一个问题。像这样,说,与-v filename=myfilename.csv

CREATE OR REPLACE FUNCTION test() RETURNS text as $$
  DECLARE 
    filepath RECORD;
  BEGIN 
    SELECT * INTO filepath from fpn(:'filename');
    COPY tablename (columnname) FROM filepath;
  END
$$ LANGUAGE plpgsql;

或者只是这个-v filepath=/full/path/to/myfilename.csv

$ psql -v filepath=/path/to/my/directory/mydatafile.data regress
regress=> COPY tablename (columnname) FROM :'filepath';
于 2012-11-06T10:56:12.690 回答