首页 文章

如何以CSV格式输出MySQL查询结果?

提问于
浏览
978

有没有一种简单的方法可以从Linux命令行运行MySQL查询并以CSV格式输出结果?

这就是我现在正在做的事情:

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

当有很多列需要用引号括起来,或者结果中有引号需要转义时,它会变得混乱 .

29 回答

  • 8

    仅Unix / Cygwin,通过'tr'管道:

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

    N.B . :它既不处理嵌入式逗号,也不处理嵌入式选项卡 .

  • 381

    MySQL Workbench可以将记录集导出为CSV,并且它似乎可以很好地处理字段中的逗号 . CSV在OpenOffice中打开很好 .

  • 0

    这很简单,它适用于任何不需要批处理模式或输出文件的东西:

    select concat_ws(',',
        concat('"', replace(field1, '"', '""'), '"'),
        concat('"', replace(field2, '"', '""'), '"'),
        concat('"', replace(field3, '"', '""'), '"'))
    
    from your_table where etc;
    

    说明:

    • 替换" with " " in each field --> replace(field1, '" ', '“”')

    • 用引号括起每个结果 - > concat(' 99789 ')

    • 在每个引用的结果之间放置一个逗号 - > concat_ws(',',quoted1,quoted2,...)

    而已!

  • 21

    此外,如果您在Bash命令行上执行查询,我相信 tr 命令可用于将默认选项卡替换为任意分隔符 .

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

  • 1502

    迄今为止,除Mysql工作台之外的所有解决方案都是错误的,并且对于mysql数据库中的至少一些可能内容而言可能是不安全的(即安全问题) .

    Mysql Workbench(以及类似的PHPMyAdmin)提供了一个正式的正确解决方案,但设计用于将输出下载到用户的位置 . 它们对于自动化数据导出等问题并不那么有用 .

    无法从 mysql -B -e 'SELECT ...' 的输出生成可靠正确的csv,因为它无法对字段中的回车符和空格进行编码 . mysql的'-s'标志确实执行反斜杠转义,并可能导致正确的解决方案 . 但是,使用脚本语言(一个具有良好的内部数据结构,而不是bash),以及编码问题已经仔细制定的库更加安全 .

    我想为此写一个脚本,但是一旦我想到了我彻底完成了什么,https://github.com/robmiller/mysql2csv的解决方案看起来很有希望 . 根据您的应用程序,指定SQL命令的yaml方法可能会或可能不会吸引人 . 为了这么简单的目的,我宁愿不保持这一点 .

    希望有人会指出一个合适的工具,这需要进行一些测试 . 否则,当我找到或写一个时,我可能会更新它 .

  • 5

    用于对CSV转储进行简单查询的微小bash脚本,受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"
    
  • 0

    这是我做的:

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

    perl脚本(从其他地方狙击)在将制表符间隔字段转换为CSV方面做得很好 .

  • 9

    要扩展以前的答案,以下单行将单个表导出为制表符分隔文件 . 它适用于自动化,每天导出数据库 .

    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
    
  • 5

    试试这段代码:

    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

    这节省了我几次 . 快,它的工作原理!

    --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
    
  • 13

    使用Tim发布的解决方案,我创建了这个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 的文件

  • 8

    除上述答案外,您还可以拥有一个使用CSV引擎的MySQL表 .

    然后,您的硬盘上将有一个文件,该文件将始终采用CSV格式,您可以在不进行处理的情况下进行复制 .

  • 3

    从命令行,您可以执行以下操作:

    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: Exporting table from Amazon RDS into a csv file

  • 25

    以下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
    
  • 31

    不完全是CSV格式,但MySQL clienttee command可用于将输出保存到 local 文件中:

    tee foobar.txt
    SELECT foo FROM bar;
    

    您可以使用 notee 禁用它 .

    SELECT … INTO OUTFILE …; 的问题是它需要在服务器上写文件的权限 .

  • 9

    在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);
    
    ?>
    
  • 34
    • 逻辑:

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

    创建CSV表时,服务器会在数据库目录中创建表格式文件 . 该文件以表名开头,扩展名为.frm . 存储引擎还会创建一个数据文件 . 它的名称以表名开头,并具有.CSV扩展名 . 数据文件是纯文本文件 . 将数据存储到表中时,存储引擎会以逗号分隔值格式将其保存到数据文件中 .

  • 1

    这是一种相当粗糙的方式 . 发现它在某个地方,不能拿任何功劳

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

    效果很好 . 再一次,虽然正则表达式证明只写 .


    正则表达式说明:

    • s ///表示替换第二个's between the first // with what'之间的//

    • "g"末尾是一个修饰符,意思是"all instance, not just first"

    • ^(在此上下文中)表示行的开头

    • $(在此上下文中)表示行尾

    所以,把它全部一起:

    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
    
  • 35

    如果您在服务器上设置了PHP,则可以使用mysql2csv导出(实际上有效的)CSV文件以进行abitrary mysql查询 . 有关更多上下文/信息,请参阅my answer at MySQL - SELECT * INTO OUTFILE LOCAL ? .

    我试图维护 mysql 中的选项名称,所以它应该足以提供 --file--query 选项:

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

    "Install" mysql2csv via

    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
    

    (下载要点的内容,检查校验和并使其可执行) .

  • 2

    什么对我有用:

    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结尾的行 .

    对于那些试图用Microsoft Excel打开csv的人来说,另一个问题是,请记住,单个单元格可以容纳32,767个字符的限制,高于它溢出到下面的行 . 要确定列中的哪些记录存在问题,请使用以下查询 . 然后,您可以截断这些记录或按照您的意愿处理它们 .

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

    Paul Tomblin给出的OUTFILE解决方案导致在MySQL服务器本身上写入文件,因此只有在您具有FILE访问权限以及登录访问权限或其他从该框中检索文件的方法时才会起作用 .

    如果你没有't have such access, and tab-delimited output is a reasonable substitute for CSV (e.g., if your end goal is to import to Excel), then Serbaut'的解决方案(使用 mysql --batch 和可选的 --raw )是要走的路 .

  • 31

    如果您正在使用的计算机上安装了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左右 .

  • 79

    您可以在SQL位置使用以下命令:

    mysql -h(hostname/IP>) -u(username) -p(password) databasename <(query.sql) > outputFILE(.txt/.xls)

    例如hostname -x.x.x.x.

    uname - 用户名

    密码 - 密码

    DBName - employeeDB

    queryFile - employee.sql

    outputFile - outputFile.xls

    mysql -hx.x.x.x -uusername -ppassword employeeDB< employee.sql> outputFile.xls

    确保从SQL所在的目录执行命令,或者在上面的命令中提及sql位置的完整路径 .

  • 9

    mysql --batch,-B使用tab作为列分隔符打印结果,每行都在一个新行上 . 使用此选项,mysql不使用历史记录文件 . 批处理模式导致非表格输出格式和特殊字符的转义 . 使用原始模式可以禁用转义;请参阅--raw选项的说明 .

    这将为您提供一个制表符分隔文件 . 由于逗号(或包含逗号的字符串)未被转义,因此将分隔符更改为逗号并不简单 .

  • 14

    本页面上的许多答案都很薄弱,因为它们无法处理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
    

    Python CSV处理功能涵盖了CSV输入格式的极端情况 .

    这可以通过流方法来改进以处理非常大的文件 .

  • 117

    来自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 将位于运行MySQL的服务器上 . 运行MySQL进程的用户必须具有写入所选目录的权限,否则命令将失败 .

    如果要从远程服务器(尤其是托管或虚拟机,如Heroku或Amazon RDS)将输出写入本地计算机,则此解决方案不适用 .

  • 5

    这个答案使用Python和流行的第三方库PyMySQL . 我'm adding it because Python'的csv库足够强大,可以正确处理 .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
    # http://stackoverflow.com/questions/12461484/is-it-secure-to-store-passwords-as-environment-variables-rather-than-as-plain-t
    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)
    
  • 181
    $ mysql your_database --password=foo < my_requests.sql > out.csv
    

    哪个是标签分隔 . 像这样管道以获得真正的CSV(感谢@therefromhere):

    ... .sql | sed 's/\t/,/g' > out.csv
    
  • 2

    怎么样:

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

相关问题