2015-04-14 9 views
6

Sto provando a scrivere uno script che copia i dati da una query a campi incrociati in un file .csv in Postgres 8.4. Sono in grado di eseguire il comando nella riga di comando psql ma quando inserisco il comando in un file ed eseguo l'operazione con l'opzione -f, viene visualizzato un errore di sintassi.Postgres: copy syntax error in .sql file

Ecco un esempio di quello che sto guardando (da this grande risposta):

CREATE TEMP TABLE t (
    section text 
,status text 
,ct  integer 
); 

INSERT INTO t VALUES 
('A', 'Active', 1), ('A', 'Inactive', 2) 
,('B', 'Active', 4), ('B', 'Inactive', 5) 
        , ('C', 'Inactive', 7); 

\copy (
SELECT * FROM crosstab(
     'SELECT section, status, ct 
     FROM t 
     ORDER BY 1,2' 
     ,$$VALUES ('Active'::text), ('Inactive')$$) 
AS ct ("Section" text, "Active" int, "Inactive" int) 
) TO 'test.csv' HEADER CSV 

Ho quindi eseguito questo e ottengo il seguente errore di sintassi:

$ psql [system specific] -f copy_test.sql 
CREATE TABLE 
INSERT 0 5 
psql:copy_test.sql:12: \copy: parse error at end of line 
psql:copy_test.sql:19: ERROR: syntax error at or near ")" 
LINE 7:) TO 'test.csv' HEADER CSV 
     ^

Un esercizio simile facendo solo una semplice query senza crosstab funziona senza incidenti.

Che cosa causa l'errore di sintassi e come posso copiare questa tabella in un file csv utilizzando il file di script?

+0

È possibile eseguire '\ copy' as-is dalla riga di comando' psql'? –

+0

corretto. Copia-incolla dritta lo fa. –

+1

Per le risate, prova a togliere tutte le nuove righe dal comando '\ copia' nel tuo file e guarda cosa succede. –

risposta

1

Come con this answer, creare una multilinea VIEW con un comando a riga singola \copy , ad es .:

CREATE TEMP TABLE t (
    section text 
,status text 
,ct  integer 
); 

INSERT INTO t VALUES 
('A', 'Active', 1), ('A', 'Inactive', 2) 
,('B', 'Active', 4), ('B', 'Inactive', 5) 
        , ('C', 'Inactive', 7); 
CREATE TEMP VIEW v1 AS 
    SELECT * FROM crosstab(
     'SELECT section, status, ct 
      FROM t 
      ORDER BY 1,2' 
     ,$$VALUES ('Active'::text), ('Inactive')$$) 
    AS ct ("Section" text, "Active" int, "Inactive" int); 

\copy (SELECT * FROM v1) TO 'test.csv' HEADER CSV 

-- optional 
DROP VIEW v1; 
0

Secondo il psqldocumentation:

-f filename

--file filename

Use the file filename as the source of commands instead of reading commands interactively. After the file is processed, psql terminates. This is in many ways equivalent to the internal command \i.

If filename is - (hyphen), then standard input is read.

Using this option is subtly different from writing psql < filename. In general, both will do what you expect, but using -f enables some nice features such as error messages with line numbers. There is also a slight chance that using this option will reduce the start-up overhead. On the other hand, the variant using the shell's input redirection is (in theory) guaranteed to yield exactly the same output that you would have gotten had you entered everything by hand.

Questo sarebbe uno di quei casi in cui l'opzione -f tratta l'ingresso in modo diverso dalla riga di comando. Rimuovendo le tue linee nuove, il reindirizzamento del file originale allo stad di psql avrebbe probabilmente funzionato.

+0

Il reindirizzamento del file su stdin genera lo stesso errore, tranne per il fatto che si è verificato l'errore nella riga 1 anziché nella riga 7. –

8

psql pensa che il primo comando sia solo \copy ( e le righe sottostanti che provengono da un'altra istruzione non correlata. I meta-comandi non sono distribuiti su più righe, perché newline è un terminatore per loro.

estratti pertinenti, relativi a psql manpage con una certa enfasi ha aggiunto:

Meta-Commands

Anything you enter in psql that begins with an unquoted backslash is a psql meta-command that is processed by psql itself. These commands make psql more useful for administration or scripting. Meta-commands are often called slash or backslash commands.
....
....(skipped)

Parsing for arguments stops at the end of the line, or when another unquoted backslash is found. An unquoted backslash is taken as the beginning of a new meta-command. The special sequence \\ (two backslashes) marks the end of arguments and continues parsing SQL commands, if any. That way SQL and psql commands can be freely mixed on a line. But in any case, the arguments of a meta-command cannot continue beyond the end of the line.

Così il primo errore è che \copy ( mancanza, quindi le linee di seguito vengono interpretati come un SELEZIONA indipendente che osserva benissimo fino linea 7, quando v'è un falso parentesi chiusa.

Come detto nei commenti, la soluzione sarebbe quella di racchiudere l'intero meta-comando in un'unica riga.

0

Le risposte elencate qui spiegano abbastanza chiaramente il ragionamento. Ecco una piccola modifica che ti permette di avere il tuo sql che contiene più righe e che lavora con psql.

# Using a file 
psql -f <(tr -d '\n' < ~/s/test.sql) 
# or 
psql < <(tr -d '\n' < ~/s/test.sql) 

# Putting the SQL using a HEREDOC 
cat <<SQL | tr -d '\n' | \psql mydatabase 
\COPY (
    SELECT 
    provider_id, 
    provider_name, 
    ... 
) TO './out.tsv' WITH(DELIMITER E'\t', NULL '',) 
SQL 
-1

è possibile modificare buffer di query utilizzando \ e meta-comando per creare più righe \ copia (...) interrogazione