将MySQL命令行结果的输出格式更改为CSV

时间:2013-03-26 14:58:05

标签: mysql csv command-line

我想在命令行上从查询输出中获取无头CSV数据。我在与MySQL服务器不同的机器上运行此查询,因此所有使用“INTO OUTFILE”的Google答案都不好。

所以我运行mysql -e "select people, places from things"。这会输出看起来像这样的东西:

+--------+-------------+
| people | places      |
+--------+-------------+
|   Bill | Raleigh, NC |
+--------+-------------+

嗯,这不好。但是,嘿,看!如果我只是将它传递给任何,它会把它变成一个以制表符分隔的列表:

people  places
Bill    Raleigh, NC

那更好 - 至少它是以编程方式解析的。但我不想要TSV,我想要CSV,而且我不想要那个标题。我可以用mysql <stuff> | tail -n +2删除标题,但如果MySQL只有一个标志可以省略它,那就太麻烦了。而且我不能用逗号替换所有标签,因为它不能处理带有逗号的内容。

那么,我怎样才能让MySQL省略标题并以CSV格式提供数据?

8 个答案:

答案 0 :(得分:80)

作为部分答案:mysql -N -B -e "select people, places from things"

-N告诉它不要打印列标题。 -B是“批处理模式”,并使用制表符分隔字段。

如果制表符分隔值不够,请参阅this Stackoverflow Q&A

答案 1 :(得分:13)

我最后编写my own command-line工具来处理这件事。它类似于cut,除了它知道如何处理引用字段等。这个工具与@Jimothy的答案配对,允许我从远程MySQL服务器获取无头CSV,我没有文件系统访问我的使用此命令的本地计算机:

$ mysql -N -e "select people, places from things" | csvm -i '\t' -o ','
Bill,"Raleigh, NC"

csvmaster on github

答案 2 :(得分:9)

如果没有其他非标准工具,可以在客户端将结果保存为CSV。 此示例仅使用 mysql客户端和awk

<强>单行:

mysql --skip-column-names --batch -e 'select * from dump3' t | awk -F'\t' '{ sep=""; for(i = 1; i <= NF; i++) { gsub(/\\t/,"\t",$i); gsub(/\\n/,"\n",$i); gsub(/\\\\/,"\\",$i); gsub(/"/,"\"\"",$i); printf sep"\""$i"\""; sep=","; if(i==NF){printf"\n"}}}'

需要做什么的逻辑解释

  1. 首先,让我们看一下 RAW模式下数据的样子(带--raw选项)。数据库和表分别是tdump3

    您可以看到从“新行”(在第一行)开始的字段由于在行中放置了新行而被拆分为三行。

  2. mysql --skip-column-names --batch --raw -e 'select * from dump3' t
    
    one line        2       new line
    quotation marks " backslash \ two quotation marks "" two backslashes \\ two tabs                new line
    the end of field
    
    another line    1       another line description without any special chars
    
    1. 以批处理模式输出数据(不含--raw选项) - 通过转发\ <tab>和{{}等字符,将每条记录更改为单行文字{1}}
    2. mysql --skip-column-names --batch -e 'select * from dump3' t
      
      one line      2  new line\nquotation marks " backslash \\ two quotation marks "" two backslashes \\\\ two tabs\t\tnew line\nthe end of field
      another line  1  another line description without any special chars
      
      1. CSV格式的数据输出
      2. 线索是使用转义字符以CSV格式保存数据。

        这样做的方法是将new-lines生成(mysql --batch作为标签\t作为反向缩进,将\\作为换行符)的特殊实体转换为每个值的等效字节(领域)。 然后整个值由\n转义,并由"括起来。 顺便说一句 - 使用相同的字符进行转义和封闭可以轻松简化输出和处理,因为您没有两个特殊字符。 因此,您需要处理的所有值(从csv格式的角度来看)都是将值"更改为"。以更常见的方式(分别转义和封闭""\),您必须先将"更改为\,然后将\\更改为{{ 1}}。

        命令'一步一步解释

        # we produce one-line output as showed in step 2.
        mysql --skip-column-names --batch -e 'select * from dump3' t
        
        # set fields separator to  because mysql produces in that way
        | awk -F'\t' 
        
        # this start iterating every line/record from the mysql data - standard behaviour of awk
        '{ 
        
        # field separator is empty because we don't print a separator before the first output field
        sep=""; 
        
        -- iterating by every field and converting the field to csv proper value
        for(i = 1; i <= NF; i++) { 
        -- note: \\ two shlashes below mean \ for awk because they're escaped
        
        -- changing \t into byte corresponding to <tab> 
            gsub(/\\t/, "\t",$i); 
        
        -- changing \n into byte corresponding to new line
            gsub(/\\n/, "\n",$i); 
        
        -- changing two \\ into one \  
            gsub(/\\\\/,"\\",$i);
        
        -- changing value into CSV proper one literally - change " into ""
            gsub(/"/,   "\"\"",$i); 
        
        -- print output field enclosed by " and adding separator before
            printf sep"\""$i"\"";  
        
        -- separator is set after first field is processed - because earlier we don't need it
            sep=","; 
        
        -- adding new line after the last field processed - so this indicates csv record separator
            if(i==NF) {printf"\n"} 
            }
        }'
        

答案 3 :(得分:9)

以上解决方案仅适用于特殊情况。嵌入式逗号,嵌入式引号以及在一般情况下使CSV变硬的其他因素,你会遇到各种各样的麻烦。

帮自己一个忙,并使用一般解决方案 - 做得对,你再也不用考虑了。一个非常强大的解决方案是csvkit命令行实用程序 - 通过Python可用于所有操作系统。通过pip install csvkit安装。这将为您提供正确的CSV数据:

    mysql -e "select people, places from things" | csvcut -t

生成以逗号分隔的数据,标题仍然存在。要删除标题行:

    mysql -e "select people, places from things" | csvcut -t | tail -n +2

产生OP要求的内容。

答案 4 :(得分:2)

mysqldump实用程序可以帮助您,基本上使用--tab选项它包含SELECT INTO OUTFILE语句。

示例:

mysqldump -u root -p --tab=/tmp world Country --fields-enclosed-by='"' --fields-terminated-by="," --lines-terminated-by="\n" --no-create-info

这将创建csv格式的文件/tmp/Country.txt

答案 5 :(得分:2)

使用sed怎么样?它是大多数(所有?)Linux操作系统的标准配置。

sed 's/\t/<your_field_delimiter>/g'

此示例使用GNU sed(Linux)。对于POSIX sed(AIX / Solaris),我相信你会输入一个文字TAB而不是\t

示例(用于CSV输出):

#mysql mysql -B -e "select * from user" | while read; do sed 's/\t/,/g'; done

localhost,root,,Y,Y,Y,Y,Y,Y,Y,Y,Y,Y,Y,Y,Y,Y,Y,Y,Y,Y,Y,Y,Y,Y,Y,Y,Y,Y,Y,Y,Y,,,,,0,0,0,0,,
localhost,bill,*2470C0C06DEE42FD1618BB99005ADCA2EC9D1E19,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,,,,,0,0,0,0,,
127.0.0.1,root,,Y,Y,Y,Y,Y,Y,Y,Y,Y,Y,Y,Y,Y,Y,Y,Y,Y,Y,Y,Y,Y,Y,Y,Y,Y,Y,Y,Y,Y,,,,,0,0,0,0,,
::1,root,,Y,Y,Y,Y,Y,Y,Y,Y,Y,Y,Y,Y,Y,Y,Y,Y,Y,Y,Y,Y,Y,Y,Y,Y,Y,Y,Y,Y,Y,,,,,0,0,0,0,,
%,jim,*2470C0C06DEE42FD1618BB99005ADCA2EC9D1E19,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,,,,,0,0,0,0,,

答案 6 :(得分:1)

mysql 客户端可以检测输出 fd,如果 fd 是 S_IFIFO(pipe) 则不输出 ASCII TABLES,如果 fd 是字符设备(S_IFCHR)则输出 ASCII TABLES。

您可以使用 --table 强制输出 ASCII 表,例如:

$mysql -t -N -h127.0.0.1 -e "select id from sbtest1 limit 1" | cat
+--------+
| 100024 |
+--------+

-t, --table 以表格格式输出。

答案 7 :(得分:0)

如果您使用的是mysql客户端,则可以设置每个会话的resultFormat,例如

mysql -h localhost -u root --resutl-format=json

mysql -h localhost -u root --vertical

查看参数here的完整列表。