首页 文章

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

提问于
浏览
51

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

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

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

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

people  places
Bill    Raleigh, NC

那个's better- at least it'以编程方式解析 . 但我不想要那个 Headers . 我可以用 mysql <stuff> | tail -n +2 删除 Headers ,但是如果MySQL只有一个标志可以省略它,那么_2554473就好了 . 我可以't just replace all tabs with commas, because that doesn'处理内容中的逗号 .

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

6 回答

  • 78

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

    -N 告诉它不要打印列 Headers . -B 是"batch mode",并使用制表符分隔字段 .

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

  • 2

    我最后写了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

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

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

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

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

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

    这产生了OP要求的内容 .

  • 13

    如何在没有其他非标准工具的情况下在客户端将结果保存为CSV . 此示例 uses only mysql 客户端和 awk .

    One-line:

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

    Logical explanation of what is needed to do

    • 首先,让我们看 how data looks like in RAW mode (带 --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
    
    • OUTPUT data in batch mode (没有 --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
    
    • data output in CSV format

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

    这样做的方法是将 mysql --batch 产生的特殊实体( \t 作为选项卡 \\ 作为反斜杠, \n 作为换行符)转换为每个值(字段)的等效字节 . 然后整个值由 " 转义并由 " 包围 . 顺便说一句 - 使用相同的字符进行转义和封闭可以轻松简化输出和处理,因为您没有两个特殊字符 . 因此,您所有与值(从csv格式的角度来看)所做的就是将 " 更改为 "" whithin值 . 以更常见的方式(分别使用转义和封闭 \" ),您必须先将 \ 更改为 \\ ,然后将 " 更改为 \" .

    commands' explanation step by step

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

    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

  • 9

    用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,,
    

相关问题