COPY with dynamic file name
Asked Answered
K

1

14

I am trying to write a function to load csv data into a table. I want the input argument to be the path to the file.

CREATE OR REPLACE FUNCTION public.loaddata(filepathname varchar)
  RETURNS void AS
$BODY$
BEGIN
COPY climatedata(
    climatestationid, 
    date,
    prcp,
    prcpqflag,
    prcpmflag,
    prcpsflag,
    tmax,
    tmaxqflag,
    tmaxmflag,
    tmaxsflag,
    tmin,
    tminqflag,
    tminmflag,
    tminsflag)
  FROM $1
  WITH csv header;
END;
$BODY$
  LANGUAGE plpgsql;

When I try to create this function I get:

syntax error at $1

What's wrong with it?

Khedive answered 15/4, 2013 at 15:51 Comment(2)
What version of Postgres?Bleareyed
You do know that postgresql's copy command has CSV parsing built in, right?Haleyhalf
B
17

COPY does not allow variable substitution. That's only possible with the core DML commands SELECT, INSERT, UPDATE, and DELETE. See:

You need dynamic SQL with EXECUTE:

CREATE OR REPLACE FUNCTION loaddata(filepathname text)
  RETURNS void
  LANGUAGE plpgsql AS
$func$
BEGIN
   EXECUTE format ('
   COPY climatedata(climatestationid, date, ..., tminsflag)  -- more columns 
   FROM %L (FORMAT CSV, HEADER)'  -- modern syntax
           -- WITH CSV HEADER'    -- tolerated legacy syntax
   , $1);  -- pass 1st function parameter (filepathname) to format() 
END
$func$;

format() requires PostgreSQL 9.1+.
Pass the file name without additional (escaped) single-quotes:

SELECT loaddata('/absolute/path/to/my/file.csv')

format() with %L quotes the file name safely. Would be susceptible to SQL injection without it.

Bleareyed answered 15/4, 2013 at 18:4 Comment(1)
That worked perfectly! I am running PostgreSQL 9.2 so the format() function was available. As I am sure you can tell I am quite new to Postgres and learning a lot as I go. I greatly appreciate the time you took to address this question. THANKS!Khedive

© 2022 - 2024 — McMap. All rights reserved.