Запрос BASH MySQL к файлу, разделенному запятыми

У меня есть следующий bash-скрипт:

#!/bin/sh

MYSQLHOST="mysql.remote-host.com"
MYSQLDB="mysqldb"
MYSQLTABLE="table"
MYSQLUSER="user"
MYSQLPASS="pass"
MYSQLDUMP="Report/report.csv"
LOG="Report/report.log"

MYSQLOPTS="--user=${MYSQLUSER} --password=${MYSQLPASS} --host=${MYSQLHOST} ${MYSQLDB}"


echo "Report Begin: $(date)"
 echo "MySQL Dump Begin: $(date)" >> ${LOG}
  echo "SELECT ${MYSQLTABLE}.created_at, ${MYSQLTABLE}.product_options FROM ${MYSQLTABLE} WHERE ${MYSQLTABLE}.product_id=1 ORDER BY ${MYSQLTABLE}.created_at" | mysql ${MYSQLOPTS} > ${MYSQLDUMP}
 echo "MySQL Dump End: $(date)" >> ${LOG}
echo "Report Successful: $(date)"

Это выводит мой запрос MySQL в файл report.csv, разделенный "TAB". Однако мне нужно, чтобы он выводился в файл, разделенный "COMMA". Я понимаю, что мог бы создать еще один скрипт для преобразования этого файла из TAB в разделяемый запятой, однако я бы предпочел сохранить этот шаг, если смогу. Итак, как я могу заставить MySQL выгружать файл в формате, разделенном запятыми?

РЕДАКТИРОВАТЬ: я нашел это решение: Как вывести результаты запроса MySQL в формате csv (на экран, а не в файл)?

Однако я не могу заставить его работать:

echo "SELECT CONCAT_WS(',', ${MYSQLTABLE}.created_at, ${MYSQLTABLE}.product_options) FROM ${MYSQLTABLE} WHERE ${MYSQLTABLE}.product_id=1 ORDER BY ${MYSQLTABLE}.created_at" | mysql ${MYSQLOPTS} > ${MYSQLDUMP}

Не работает :(


person BassKozz    schedule 20.09.2009    source источник


Ответы (5)


Запустите следующее:

echo "SELECT CONCAT_WS(',', ${MYSQLTABLE}.created_at, ${MYSQLTABLE}.product_options) FROM ${MYSQLTABLE} WHERE ${MYSQLTABLE}.product_id=1 ORDER BY ${MYSQLTABLE}.created_at" | \
mysql ${MYSQLOPTS}  | tr '\t' ',' > ${MYSQLDUMP}

Команда tr заменяет один символ другим.

person David Rabinowitz    schedule 21.09.2009

Для этого вам не нужен другой скрипт. Просто измените:

> ${MYSQLDUMP}

в конце вашей строки читать:

| sed 's/\x09/,/g' > ${MYSQLDUMP}

Но вы должны быть осторожны, чтобы в ваших данных не было запятых, иначе они будут неправильно распознаны тем, что использует файл CSV (но у вас уже может быть эта проблема с вкладками).

person Community    schedule 20.09.2009
comment
К сожалению, это не работает :( Поле product_options содержит элементы, которые выбираются командой sed, и разбивает их на новые столбцы :( - person BassKozz; 21.09.2009

Почему бы не использовать

SELECT ${MYSQLTABLE}.created_at, ${MYSQLTABLE}.product_options INTO outfile '${MYSQLDUMP}' FROM ${MYSQLTABLE} FIELDS TERMINATED BY ',' OPTIONALLY ENCLOSED BY '"' LINES TERMINATED BY '\n' WHERE ${MYSQLTABLE}.product_id=1 ORDER BY ${MYSQLTABLE}.created_at
person pfyon    schedule 21.09.2009
comment
Посмотрите на комментарии, оставленные в Ответе Билла Карвина. Я не могу, потому что это удаленный сервер, на котором размещена база данных mysql, и у меня нет прав на чтение/запись. - person BassKozz; 21.09.2009

Вот пример SQL-запроса, который выводит в формате, разделенном запятыми файл:

SELECT a,b,a+b INTO OUTFILE '/tmp/result.txt'
  FIELDS TERMINATED BY ',' OPTIONALLY ENCLOSED BY '"'
  LINES TERMINATED BY '\n'
  FROM test_table;

Комментарий к комментариям: Достаточно честно, синтаксис INTO OUTFILE записывает в файл на хосте сервера базы данных, а не на хосте, на котором запущен сценарий оболочки и клиент mysql.

Клиент mysql не имеет режима вывода csv, он имеет только табличный формат штрихов и тире (с флагами --table или -t), формат, разделенный табуляцией (с флагами --batch или -B), формат HTML (--html или -H) и XML (--xml или -X).

Если в вашей базе данных есть контент, содержащий вкладки, то либо преобразуйте вкладки во что-то другое с помощью функции REPLACE() SQL, либо выведите в одном из других форматов и попытайтесь преобразовать это в csv:

mysql ... --table --skip-column-names |
sed -e 's/  *|  */,/g' \
    -e 's/^|  *//' \
    -e 's/  *|$//' \
    -e '/^+--/d'
person Bill Karwin    schedule 20.09.2009
comment
То пишет в файл на сервере, а не в стандартный аут. - person staticsan; 21.09.2009
comment
@staticsan: Да, ты прав. Но обратите внимание на MYSQLHOST=localhost в вопросе ОП. - person Bill Karwin; 21.09.2009
comment
Я не могу заставить его работать: echo SELECT ${MYSQLTABLE}.created_at, ${MYSQLTABLE}.product_options INTO OUTFILE 'Report/tmp2.csv' FIELDS TERMINATED BY ',' НЕОБЯЗАТЕЛЬНО ЗАКРЫТЫЙ '' LINES TERMINATED BY '\n ' FROM ${MYSQLTABLE} WHERE ${MYSQLTABLE}.product_id=1 ORDER BY ${MYSQLTABLE}.created_at | mysql ${MYSQLOPTS} › ${MYSQLDUMP} Я получаю: ./report.sh: строка 28: неожиданный EOF при поиске соответствия `'' ./report.sh: строка 33: синтаксическая ошибка: неожиданный конец файла - person BassKozz; 21.09.2009
comment
Удалите пункт OPTIONALLY ENCLOSED BY '"'. Вам не нужны поля, заключенные в двойные кавычки, и это, вероятно, является причиной несбалансированных кавычек в вашем сценарии оболочки. - person Bill Karwin; 21.09.2009
comment
У staticsan есть смысл ... Я поместил туда локальный хост, но это не совсем правда, БД MYSQL хранится на УДАЛЕННОМ сервере, поэтому это не сработает :( Я получаю следующее, когда я пытался после удаления НЕОБЯЗАТЕЛЬНО ЗАКРЫТ: ОШИБКА 1045 (28000) в строке 1: Доступ запрещен для пользователя «пользователь» @ «123.456.789.0/255.255.254.0» (с использованием пароля: ДА) - person BassKozz; 21.09.2009
comment
Извините, я не был уверен в этом с самого начала, я не думал, что это будет проблемой. - person BassKozz; 21.09.2009
comment
Я отредактировал свой первоначальный вопрос, чтобы отразить удаленный хост - person BassKozz; 21.09.2009

Нашел простой однострочный Perl, который, кажется, помогает:

perl -F"\t" -lane 'print join ",", map {s/"/""/g; /^[\d.]+$/ ? $_ : qq("$_")} @F '

-Perl-скрипт

Итак, строка в моем скрипте выглядит так:

        echo "SELECT ${MYSQLTABLE}.created_at, ${MYSQLTABLE}.product_options FROM ${MYSQLTABLE} WHERE ${MYSQLTABLE}.product_id=1 ORDER BY ${MYSQLTABLE}.created_at" | mysql ${MYSQLOPTS} | perl -F"\t" -lane 'print join ",", map {s/"/""/g; /^[\d.]+$/ ? $_ : qq("$_")} @F ' > ${MYSQLDUMP}

Спасибо за всю помощь, особенно от Билла Карвина, я хотел добавить VoteUp к вашему ответу, но у меня недостаточно репутации :( Как только я получу больше представителей, я вернусь и проголосую за ваш ответ. Еще раз спасибо.

person BassKozz    schedule 21.09.2009