Postgres: копировать синтаксическую ошибку.sql файл

Я пытаюсь написать скрипт, который копирует данные из перекрестного запроса .csv файл в Postgres 8.4. Я могу запустить команду в командной строке psql, но когда я помещаю команду в файл и запускаю ее с помощью , Я получаю синтаксическую ошибку.

вот пример того, на что я смотрю (из этой отличный ответ):

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

затем я запускаю это и получаю следующую синтаксическую ошибку:

$ 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
        ^

аналогичное упражнение просто простой запрос без перекрестной таблицы работает без инцидентов.

что вызывает синтаксическую ошибку и как я могу скопировать эту таблицу в файл csv с помощью файла сценария?

4 ответов


С ответ создать мульти-строку VIEW С , например:

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;

psql думает, что ваша первая команда просто \copy ( и строки ниже, которые из другого несвязанного оператора. Мета-команды не распространяются на несколько строк, потому что newline является Терминатором для них.

соответствующие выдержки из psql manpage С некоторым акцентом добавлено:

Мета-Команд

все, что вы вводите в psql, которое начинается с некотируемой обратной косой черты, является psql meta-команда, которая обрабатывается psql себя. Эта команда сделать команду psql более полезным для администрирования или скриптов. Мета-команды часто называются командами slash или backslash.
....
....(пропущено)

разбор аргументов останавливается в конце строки, или когда другой unquoted обратная косая черта найдена. Без кавычек обратная косая черта берется как начало новой мета-команды. Специальная последовательность \\ (два обратные косые черты) отмечает конец аргументов и продолжает синтаксический анализ SQL команды, если таковые имеются. Таким образом, команды SQL и psql могут быть свободно смешаны на линии. но в любом случае аргументы мета-команды не могут продолжайте дальше конца строки.

Итак, первая ошибка заключается в том, что \copy ( сбой, затем строки ниже интерпретируются как независимый выбор, который выглядит нормально до строки 7, когда есть ложная закрывающая скобка.

как сказано в комментариях, исправление будет заключаться в том, чтобы втиснуть всю мета-команду в одну линию.


По словам psql документация:

-Ф именем

--file filename

используйте имя файла в качестве источника команд вместо чтения команд в интерактивном режиме. После обработки файла psql завершает работу. Это во многом эквивалентно внутренней команде \i.

Если имя файла - (дефис), то считывается стандартный ввод.

использование этой опции тонко отличается от написания psql

Это будет один из тех случаев, когда the -f опция обрабатывает ваш ввод иначе, чем в командной строке. Удаление ваших новых строк работало, перенаправляя исходный файл на psql's stdin, вероятно, также сработал бы.


ответы, перечисленные здесь, объясняют рассуждения довольно ясно. Вот небольшой хак, который позволяет вам иметь ваш sql содержит несколько строк и работать с 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