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

spi*_*ech 57 mysql csv command-line

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

所以我跑了mysql -e "select people, places from things".那输出看起来像这样的东西:

+--------+-------------+
| people | places      |
+--------+-------------+
|   Bill | Raleigh, NC |
+--------+-------------+
Run Code Online (Sandbox Code Playgroud)

嗯,这不好.但是,嘿,看!如果我只是把它管道到任何东西,它会把它变成一个以制表符分隔的列表:

people  places
Bill    Raleigh, NC
Run Code Online (Sandbox Code Playgroud)

那更好 - 至少它是以编程方式解析的.但我不想要TSV,我想要CSV,而且我不想要那个标题.我可以摆脱标题mysql <stuff> | tail -n +2,但这是一个麻烦我想避免如果MySQL只有一个标志来省略它.而且我不能用逗号替换所有选项卡,因为它不处理带有逗号的内容.

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

Jim*_*thy 85

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

-N告诉它不要打印列标题.-B是"批处理模式",并使用选项卡分隔字段.

如果制表符分隔值不够,请参阅此Stackoverflow问答.


spi*_*ech 13

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

$ mysql -N -e "select people, places from things" | csvm -i '\t' -o ','
Bill,"Raleigh, NC"
Run Code Online (Sandbox Code Playgroud)

github上的csvmaster

  • 编写自定义实用程序并不能真正帮助那些不能(或不想)下载和构建它的人.我认为另一个答案更具实用性. (4认同)

Chr*_*son 10

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

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

    mysql -e "select people, places from things" | csvcut -t
Run Code Online (Sandbox Code Playgroud)

这会产生以逗号分隔的数据,标题仍然存在.要删除标题行:

    mysql -e "select people, places from things" | csvcut -t | tail -n +2
Run Code Online (Sandbox Code Playgroud)

这产生了OP要求的内容.

  • 正是我想要的!并且(基于http://stackoverflow.com/questions/356578/how-to-output-mysql-query-results-in-csv-format),您可以同时生成一个本地CSV文件,例如: -e“从事物中选择人,地方” | csvcut -t&gt; output.csv` (2认同)

Art*_*ara 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

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

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. 批处理模式下的OUTPUT数据(无--raw选项) - 通过转义字符\ <tab>和,将每个记录更改为单行文本new-lines
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格式输出数据

线索是使用转义字符以CSV格式保存数据.

做到这一点的方法是将转换哪个特殊实体mysql --batch产生(\t如凸片\\作为backshlash和\n作为新行)成每个值(字段)等效字节.然后整个值被转义并被"封闭".顺便说一句 - 使用相同的字符进行转义和封闭可以轻松简化输出和处理,因为您没有两个特殊字符.因此,您需要处理的所有值(从csv格式的角度来看)都要更改"""whithin值.在更普遍的方式(与逃逸,分别封闭\"),您必须首先改变\\\,然后改变"\".

并且命令的解释一步一步:

# 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"} 
    }
}'

  • 确切地说,这就是解决方案**没有**"--raw"选项的原因.它仅在第一步中用于显示确切数据. (2认同)