it-swarm.com.ru

Как вывести результаты запроса MySQL в формате CSV?

Есть ли простой способ выполнить запрос MySQL из командной строки Linux и вывести результаты в CSV формате?

Вот что я делаю сейчас:

mysql -u uid -ppwd -D dbname << EOQ | sed -e 's/        /,/g' | tee list.csv
select id, concat("\"",name,"\"") as name
from students
EOQ

Это становится грязным, когда есть много столбцов, которые должны быть заключены в кавычки, или если в результатах есть кавычки, которые нужно экранировать.

1004
MCS

От http://www.tech-recipes.com/rx/1475/save-mysql-query-results-into-a-text-or-csv-file/

SELECT order_id,product_name,qty
FROM orders
WHERE foo = 'bar'
INTO OUTFILE '/var/lib/mysql-files/orders.csv'
FIELDS TERMINATED BY ','
ENCLOSED BY '"'
LINES TERMINATED BY '\n';

С помощью этой команды имена столбцов не будут экспортированы.

Также обратите внимание, что /var/lib/mysql-files/orders.csv будет на server под управлением MySQL. Пользователь, под которым запущен процесс MySQL, должен иметь права на запись в выбранный каталог, иначе команда не будет выполнена.

Если вы хотите записать вывод на локальный компьютер с удаленного сервера (особенно с размещенной или виртуализированной машины, такой как Heroku или Amazon RDS), это решение не подходит.

1540
Paul Tomblin
$ mysql your_database --password=foo < my_requests.sql > out.csv

Который разделен табуляцией. Передайте это так, чтобы получить настоящий CSV (спасибо @therefromhere): 

... .sql | sed 's/\t/,/g' > out.csv
391
Stan

mysql --batch, -B

Печатайте результаты, используя табуляцию в качестве разделителя столбцов, с каждой строкой в ​​ новая линия. С этой опцией mysql не использует файл истории . Пакетный режим приводит к нетабличному формату вывода и экранированию специальные символы. Экранирование может быть отключено с помощью необработанного режима; увидеть описание параметра --raw.

Это даст вам файл, разделенный табуляцией. Поскольку запятые (или строки, содержащие запятую) не экранированы, изменить разделитель на запятую не так просто.

184
serbaut

Вот довольно грубый способ сделать это. Нашел где-то, не могу взять кредит

mysql --user=wibble --password wobble -B -e "select * from vehicle_categories;" | sed "s/'/\'/;s/\t/\",\"/g;s/^/\"/;s/$/\"/;s/\n//g" > vehicle_categories.csv

Работает довольно хорошо. Еще раз, хотя регулярное выражение доказывает только запись.


Regex Объяснение:

  • s /// означает заменить то, что находится между первым // на то, что между вторым //
  • «g» в конце - это модификатор, который означает «все экземпляры, а не только первые»
  • ^ (в этом контексте) означает начало строки
  • $ (в этом контексте) означает конец строки

Итак, складывая все вместе:

s/'/\'/          replace ' with \'
s/\t/\",\"/g     replace all \t (tab) with ","
s/^/\"/          at the beginning of the line place a "
s/$/\"/          at the end of the line place a "
s/\n//g          replace all \n (newline) with nothing
118
Tim Harding

Unix / Cygwin only, передать его через 'tr':

mysql <database> -e "<query here>" | tr '\t' ',' > data.csv

N.B .: Это не обрабатывает ни встроенные запятые, ни вкладки.

79
strickli

Это спасло меня пару раз. Быстро и все работает!

--batch

--raw

Пример:

Sudo mysql -udemo_user -p -h127.0.0.1 --port=3306 \
   --default-character-set=utf8 --database=demo_database \
   --batch --raw < /var/demo_sql_query.sql > /var/demo_csv_export.csv
36
hrvoj3e

Решение OUTFILE, данное Полом Томблиным (Paul Tomblin), приводит к тому, что файл записывается на самом сервере MySQL, поэтому он будет работать только при наличии FILE access, а также доступа к логину или других средств для извлечения файла из коробка.

Если у вас нет такого доступа, и вывод с разделителями табуляцией является разумной заменой CSV (например, если ваша конечная цель - импортировать в Excel), то решение Serbaut (с использованием mysql --batch и, возможно, --raw) - путь.

35
Leland Woodbury

MySQL Workbench может экспортировать наборы записей в CSV, и кажется, что он очень хорошо обрабатывает запятые в полях. CSV открывается в OpenOffice нормально.

32
David Oliver

Как насчет: 

mysql your_database -p < my_requests.sql | awk '{print $1","$2}' > out.csv
31
Steve

Все решения, представленные на сегодняшний день, кроме решения Mysql Workbench, являются некорректными и, возможно, небезопасными (например, проблемы безопасности), по крайней мере, для некоторого возможного содержимого в базе данных mysql.

Mysql Workbench (и аналогично PHPMyAdmin) предоставляют формально правильное решение, но предназначены для загрузки вывода в местоположение пользователя. Они не так полезны для таких вещей, как автоматизация экспорта данных.

Невозможно сгенерировать надежно правильный csv из вывода mysql -B -e 'SELECT ...', потому что это не может кодировать возврат каретки и пробел в полях. Флаг '-s' для mysql действительно экранирует обратную косую черту и может привести к правильному решению. Тем не менее, использование языка сценариев (язык с приличными внутренними структурами данных, а не bash) и библиотек, где проблемы кодирования уже были тщательно проработаны, гораздо безопаснее.

Я подумал о написании сценария для этого, но как только я подумал о том, что я бы назвал, мне пришло в голову искать уже существующую работу с тем же именем. Несмотря на то, что я не прошел через это полностью, решение на https://github.com/robmiller/mysql2csv выглядит многообещающим. В зависимости от вашего приложения, подход yaml к указанию команд SQL может или не может понравиться. Я также не в восторге от требования более свежей версии Ruby, чем стандартная комплектация для моего ноутбука Ubuntu 12.04 или серверов Debian Squeeze. Да, я знаю, что мог бы использовать RVM, но я бы предпочел не поддерживать это для такой простой цели.

Надеюсь, кто-то укажет подходящий инструмент, который прошел небольшое тестирование. В противном случае я, вероятно, обновлю это, когда найду или напишу.

25
mc0e

Из вашей командной строки Вы можете сделать это:

mysql -h *hostname* -P *port number* --database=*database_name* -u *username* -p -e *your SQL query* | sed 's/\t/","/g;s/^/"/;s/$/"/;s/\n//g' > *output_file_name.csv*

Credits:Экспорт таблицы из Amazon RDS в CSV-файл

22
Sri Murthy Upadhyayula

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

Вот простое и сильное решение в Python:

#!/usr/bin/env python

import csv
import sys

tab_in = csv.reader(sys.stdin, dialect=csv.Excel_tab)
comma_out = csv.writer(sys.stdout, dialect=csv.Excel)

for row in tab_in:
    comma_out.writerow(row)

Назовите этот файл tab2csv, поместите его в свой путь, дайте ему разрешения на выполнение, затем используйте его, перечислите это:

mysql OTHER_OPTIONS --batch --execute='select * from whatever;' | tab2csv >outfile.csv

Функции обработки CSV в Python покрывают угловые случаи для формата (ов) ввода CSV.

Это может быть улучшено для обработки очень больших файлов с помощью потокового подхода.

16
Chris Johnson
  1. логика:

CREATE TABLE () (SELECT data FROM other_table ) ENGINE=CSV ; 

При создании таблицы CSV сервер создает файл формата таблицы в каталог базы данных. Файл начинается с имени таблицы и имеет расширение .frm. Механизм хранения также создает файл данных. Его имя начинается с имени таблицы и имеет расширение .CSV. Файл данных простой текстовый файл. Когда вы храните данные в таблице, хранилище Движок сохраняет его в файл данных в формате значений, разделенных запятыми.

13
zloctb

В качестве альтернативы ответу выше, у вас может быть таблица MySQL, использующая механизм CSV.

Тогда у вас будет файл на жестком диске, который всегда будет в формате CSV, который вы можете просто скопировать без обработки.

9
Jonathan

Это просто и работает с чем угодно, не требуя пакетного режима или выходных файлов:

select concat_ws(',',
    concat('"', replace(field1, '"', '""'), '"'),
    concat('"', replace(field2, '"', '""'), '"'),
    concat('"', replace(field3, '"', '""'), '"'))

from your_table where etc;

Объяснение:

  1. Замените «на» в каждом поле -> replace (field1, '"', '" "')
  2. Заключите каждый результат в кавычки -> concat ('", result1,'" ')
  3. Поместите запятую между каждым цитируемым результатом -> concat_ws (',', quoted1, quoted2, ...)

Это оно!

9
Marty Hirsch

Этот ответ использует Python и популярную стороннюю библиотеку, PyMySQL . Я добавляю его, потому что библиотека csv в Python достаточно мощная, чтобы правильно обрабатывать множество различных разновидностей .csv, и никакие другие ответы не используют код Python для взаимодействия с базой данных.

import contextlib
import csv
import datetime
import os

# https://github.com/PyMySQL/PyMySQL
import pymysql

SQL_QUERY = """
SELECT * FROM my_table WHERE my_attribute = 'my_attribute';
"""

# embedding passwords in code gets nasty when you use version control
# the environment is not much better, but this is an example
# https://stackoverflow.com/questions/12461484
SQL_USER = os.environ['SQL_USER']
SQL_PASS = os.environ['SQL_PASS']

connection = pymysql.connect(Host='localhost',
                             user=SQL_USER,
                             password=SQL_PASS,
                             db='dbname')

with contextlib.closing(connection):
    with connection.cursor() as cursor:
        cursor.execute(SQL_QUERY)
        # Hope you have enough memory :)
        results = cursor.fetchall()

output_file = 'my_query-{}.csv'.format(datetime.datetime.today().strftime('%Y-%m-%d'))
with open(output_file, 'w', newline='') as csvfile:
    # http://stackoverflow.com/a/17725590/2958070 about lineterminator
    csv_writer = csv.writer(csvfile, lineterminator='\n')
    csv_writer.writerows(results)
9
Ben

Чтобы развернуть предыдущие ответы, следующий однострочный файл экспортирует одну таблицу в виде файла, разделенного табуляцией. Это подходит для автоматизации, экспорт базы данных каждый день или около того.

mysql -B -D mydatabase -e 'select * from mytable'

Удобно, что мы можем использовать ту же технику для вывода списка таблиц MySQL и описания полей в одной таблице:

mysql -B -D mydatabase -e 'show tables'

mysql -B -D mydatabase -e 'desc users'

Field   Type    Null    Key Default Extra
id  int(11) NO  PRI NULL    auto_increment
email   varchar(128)    NO  UNI NULL    
lastName    varchar(100)    YES     NULL    
title   varchar(128)    YES UNI NULL    
userName    varchar(128)    YES UNI NULL    
firstName   varchar(100)    YES     NULL    
8
johntellsall

Кроме того, если вы выполняете запрос в командной строке Bash, я считаю, что команду tr можно использовать для замены вкладок по умолчанию на произвольные разделители.

$ echo "SELECT * FROM Table123" | mysql Database456 | tr "\t" ,

7
Brian

Опираясь на user7610, вот лучший способ сделать это. С mysql outfile было 60 минут владения файлом и проблем с перезаписью. 

Это не круто, но это сработало за 5 минут.

php csvdump.php localhost root password database tablename > whatever-you-like.csv

<?php

$server = $argv[1];
$user = $argv[2];
$password = $argv[3];
$db = $argv[4];
$table = $argv[5];

mysql_connect($server, $user, $password) or die(mysql_error());
mysql_select_db($db) or die(mysql_error());

// fetch the data
$rows = mysql_query('SELECT * FROM ' . $table);
$rows || die(mysql_error());


// create a file pointer connected to the output stream
$output = fopen('php://output', 'w');

// output the column headings

$fields = [];
for($i = 0; $i < mysql_num_fields($rows); $i++) {
    $field_info = mysql_fetch_field($rows, $i);
    $fields[] = $field_info->name;
}
fputcsv($output, $fields);

// loop over the rows, outputting them
while ($row = mysql_fetch_assoc($rows)) fputcsv($output, $row);

?>
6
Michael Cole

Не совсем как формат CSV, но tee команда из MySQL client может использоваться для сохранения вывода в файл local:

tee foobar.txt
SELECT foo FROM bar;

Вы можете отключить его, используя notee.

Проблема с SELECT … INTO OUTFILE …; заключается в том, что ему требуется разрешение на запись файлов на сервер.

5
Denilson Sá Maia

Вот что я делаю:

echo $QUERY | \
  mysql -B  $MYSQL_OPTS | \
  Perl -F"\t" -lane 'print join ",", map {s/"/""/g; /^[\d.]+$/ ? $_ : qq("$_")} @F ' | \
  mail -s 'report' [email protected]

Скрипт Perl (снятый откуда-то еще) хорошо выполняет преобразование полей с табуляцией в CSV.

5
extraplanetary

Используя решение, опубликованное Тимом, я создал этот сценарий bash, чтобы упростить процесс (запрашивается пароль root, но вы можете легко изменить сценарий для запроса любого другого пользователя):

#!/bin/bash

if [ "$1" == "" ];then
    echo "Usage: $0 DATABASE TABLE [MYSQL EXTRA COMMANDS]"
    exit
fi

DBNAME=$1
TABLE=$2
FNAME=$1.$2.csv
MCOMM=$3

echo "MySQL password:"
stty -echo
read PASS
stty echo

mysql -uroot -p$PASS $MCOMM $DBNAME -B -e "SELECT * FROM $TABLE;" | sed "s/'/\'/;s/\t/\",\"/g;s/^/\"/;s/$/\"/;s/\n//g" > $FNAME

Это создаст файл с именем: database.table.csv

3
lepe

Если вы настроили PHP на сервере, вы можете использовать mysql2csv , чтобы экспортировать (действительно действительный) файл CSV для произвольного запроса MySQL. Смотрите мой ответ на MySQL - ВЫБРАТЬ * В ЛОКАЛЬНОМ OUTFILE? немного больше контекста/информации.

Я попытался сохранить имена опций из mysql, поэтому их должно быть достаточно для предоставления опций --file и --query:

./mysql2csv --file="/tmp/result.csv" --query='SELECT 1 as foo, 2 as bar;' --user="username" --password="password"

"Установить" mysql2csv через

wget https://Gist.githubusercontent.com/paslandau/37bf787eab1b84fc7ae679d1823cf401/raw/29a48bb0a43f6750858e1ddec054d3552f3cbc45/mysql2csv -O mysql2csv -q && (sha256sum mysql2csv | cmp <(echo "b109535b29733bd596ecc8608e008732e617e97906f119c66dd7cf6ab2865a65  mysql2csv") || (echo "ERROR comparing hash, Found:" ;sha256sum mysql2csv) ) && chmod +x mysql2csv

(загрузите содержимое Gist, проверьте контрольную сумму и сделайте ее исполняемой).

3
Hirnhamster

Попробуйте этот код:

SELECT 'Column1', 'Column2', 'Column3', 'Column4', 'Column5'
UNION ALL
SELECT column1, column2,
column3 , column4, column5 FROM demo
INTO OUTFILE '/tmp/demo.csv'
FIELDS TERMINATED BY ','
ENCLOSED BY '"'
LINES TERMINATED BY '\n';

Для получения дополнительной информации: http://dev.mysql.com/doc/refman/5.1/en/select-into.html

1
Indrajeet Singh

Крошечный bash-скрипт для выполнения простого запроса к дампам CSV, вдохновленный https://stackoverflow.com/a/5395421/2841607 .

#!/bin/bash

# $1 = query to execute
# $2 = outfile
# $3 = mysql database name
# $4 = mysql username

if [ -z "$1" ]; then
    echo "Query not given"
    exit 1
fi

if [ -z "$2" ]; then
    echo "Outfile not given"
    exit 1
fi

MYSQL_DB=""
MYSQL_USER="root"

if [ ! -z "$3" ]; then
    MYSQL_DB=$3
fi

if [ ! -z "$4" ]; then
    MYSQL_USER=$4
fi

if [ -z "$MYSQL_DB" ]; then
    echo "Database name not given"
    exit 1
fi

if [ -z "$MYSQL_USER" ]; then
    echo "Database user not given"
    exit 1
fi

mysql -u $MYSQL_USER -p -D $MYSQL_DB -B -s -e "$1" | sed "s/'/\'/;s/\t/\",\"/g;s/^/\"/;s/$/\"/;s/\n//g" > $2
echo "Written to $2"
1
minitauros

Следующий скрипт bash работает для меня. Опционально также получает схему для запрошенных таблиц.

#!/bin/bash
#
# export mysql data to CSV
#https://stackoverflow.com/questions/356578/how-to-output-mysql-query-results-in-csv-format
#

#ansi colors
#http://www.csc.uvic.ca/~sae/seng265/fall04/tips/s265s047-tips/bash-using-colors.html
blue='\033[0;34m'
red='\033[0;31m'
green='\033[0;32m' # '\e[1;32m' is too bright for white bg.
endColor='\033[0m'

#
# a colored message 
#   params:
#     1: l_color - the color of the message
#     2: l_msg - the message to display
#
color_msg() {
  local l_color="$1"
  local l_msg="$2"
  echo -e "${l_color}$l_msg${endColor}"
}


#
# error
#
# show the given error message on stderr and exit
#
#   params:
#     1: l_msg - the error message to display
#
error() {
  local l_msg="$1"
  # use ansi red for error
  color_msg $red "Error:" 1>&2
  color_msg $red "\t$l_msg" 1>&2
  usage
}

#
# display usage 
#
usage() {
  echo "usage: $0 [-h|--help]" 1>&2
  echo "               -o  | --output      csvdirectory"    1>&2
  echo "               -d  | --database    database"   1>&2
  echo "               -t  | --tables      tables"     1>&2
  echo "               -p  | --password    password"   1>&2
  echo "               -u  | --user        user"       1>&2
  echo "               -hs | --Host        Host"       1>&2
  echo "               -gs | --get-schema"             1>&2
  echo "" 1>&2
  echo "     output: output csv directory to export mysql data into" 1>&2
  echo "" 1>&2
  echo "         user: mysql user" 1>&2
  echo "     password: mysql password" 1>&2
  echo "" 1>&2
  echo "     database: target database" 1>&2
  echo "       tables: tables to export" 1>&2
  echo "         Host: Host of target database" 1>&2
  echo "" 1>&2
  echo "  -h|--help: show help" 1>&2
  exit 1
}

#
# show help 
#
help() {
  echo "$0 Help" 1>&2
  echo "===========" 1>&2
  echo "$0 exports a csv file from a mysql database optionally limiting to a list of tables" 1>&2
  echo "   example: $0 --database=cms --user=scott --password=tiger  --tables=person --output person.csv" 1>&2
  echo "" 1>&2
  usage
}

domysql() {
  mysql --Host $Host -u$user --password=$password $database
}

getcolumns() {
  local l_table="$1"
  echo "describe $l_table" | domysql | cut -f1 | grep -v "Field" | grep -v "Warning" | paste -sd "," - 2>/dev/null
}

Host="localhost"
mysqlfiles="/var/lib/mysql-files/"

# parse command line options
while true; do
  #echo "option $1"
  case "$1" in
    # options without arguments
    -h|--help) usage;;
    -d|--database)     database="$2" ; shift ;;
    -t|--tables)       tables="$2" ; shift ;;
    -o|--output)       csvoutput="$2" ; shift ;;
    -u|--user)         user="$2" ; shift ;;
    -hs|--Host)        Host="$2" ; shift ;;
    -p|--password)     password="$2" ; shift ;;
    -gs|--get-schema)  option="getschema";; 
    (--) shift; break;;
    (-*) echo "$0: error - unrecognized option $1" 1>&2; usage;;
    (*) break;;
  esac
  shift
done

# checks
if [ "$csvoutput" == "" ]
then
  error "ouput csv directory not set"
fi
if [ "$database" == "" ]
then
  error "mysql database not set"
fi
if [ "$user" == "" ]
then
  error "mysql user not set"
fi
if [ "$password" == "" ]
then
  error "mysql password not set"
fi

color_msg $blue "exporting tables of database $database"
if [ "$tables" = "" ]
then
tables=$(echo "show tables" | domysql)
fi

case $option in
  getschema) 
   rm $csvoutput$database.schema
   for table in $tables
   do
     color_msg $blue "getting schema for $table"
     echo -n "$table:" >> $csvoutput$database.schema
     getcolumns $table >> $csvoutput$database.schema
   done  
   ;;
  *)
for table in $tables
do
  color_msg $blue "exporting table $table"
  cols=$(grep "$table:" $csvoutput$database.schema | cut -f2 -d:)
  if [  "$cols" = "" ]
  then
    cols=$(getcolumns $table)
  fi
  ssh $Host rm $mysqlfiles/$table.csv
cat <<EOF | mysql --Host $Host -u$user --password=$password $database 
SELECT $cols FROM $table INTO OUTFILE '$mysqlfiles$table.csv'
FIELDS TERMINATED BY ','
ENCLOSED BY '"'
LINES TERMINATED BY '\n';
EOF
  scp $Host:$mysqlfiles/$table.csv $csvoutput$table.csv.raw
  (echo "$cols"; cat $csvoutput$table.csv.raw) > $csvoutput$table.csv
  rm $csvoutput$table.csv.raw
done
  ;;
esac
1
Wolfgang Fahl

Если на используемом вами компьютере установлен PHP, вы можете написать скрипт PHP для этого. Это требует установки PHP с установленным расширением MySQL.

Вы можете вызвать интерпретатор PHP из командной строки следующим образом:

php --php-ini path/to/php.ini your-script.php

Я включаю переключатель --php-ini, потому что вам может потребоваться использовать собственную конфигурацию PHP, которая включает расширение MySQL. В PHP 5.3.0+ это расширение включено по умолчанию, поэтому больше нет необходимости использовать конфигурацию для его включения.

Затем вы можете написать свой скрипт экспорта как любой обычный скрипт PHP:

<?php
    #mysql_connect("localhost", "username", "password") or die(mysql_error());
    mysql_select_db("mydb") or die(mysql_error());

    $result = mysql_query("SELECT * FROM table_with_the_data p WHERE p.type = $typeiwant");

    $result || die(mysql_error());

    while($row = mysql_fetch_row($result)) {
      $comma = false;
      foreach ($row as $item) {

        # Make it comma separated
        if ($comma) {
          echo ',';
        } else {
          $comma = true;
        }

        # Quote the quotes
        $quoted = str_replace("\"", "\"\"", $item);

        # Quote the string
        echo "\"$quoted\"";
      }
        echo "\n";
    }
?>

Преимущество этого метода в том, что у него нет проблем с полями varchar и text, в которых есть текст, содержащий символы новой строки. Эти поля правильно указаны, и эти символы новой строки в них будут интерпретироваться читателем CSV как часть текста, а не разделители записей. Это то, что потом трудно исправить с помощью sed или так.

0
user7610

Что сработало для меня:

SELECT *
FROM students
WHERE foo = 'bar'
LIMIT 0,1200000
INTO OUTFILE './students-1200000.csv'
FIELDS TERMINATED BY ',' ESCAPED BY '"'
ENCLOSED BY '"'
LINES TERMINATED BY '\r\n';

Ни одно из решений в этом потоке не работало для моего конкретного случая, у меня были красивые данные json внутри одного из столбцов, которые могли быть испорчены в моем выводе CSV. Для тех, у кого похожая проблема, попробуйте строки, оканчивающиеся на\r\n.

Еще одна проблема для тех, кто пытается открыть CSV-файл с помощью Microsoft Excel, имейте в виду, что существует ограничение в 32 767 символов, которое может содержать одна ячейка, при этом она переполняется до следующих строк. Чтобы определить, какие записи в столбце имеют проблему, используйте запрос ниже. Затем вы можете обрезать эти записи или обработать их, как хотите.

SELECT id,name,CHAR_LENGTH(json_student_description) AS 'character length'
FROM students
WHERE CHAR_LENGTH(json_student_description)>32767;
0
Rohit Chemburkar