【问题标题】:MySQL export into outfile : CSV escaping charsMySQL 导出到 outfile:CSV 转义字符
【发布时间】:2010-11-10 07:08:19
【问题描述】:

我有一个包含一些常见字段的时间表数据库表。

id, client_id, project_id, task_id, description, time, date 

还有更多,但这就是它的要点。

我在一夜之间在该表上运行导出到 CSV 文件,以便为用户提供其数据的备份。它还用作带有一些自定义报告的宏 Excel 文件的数据导入。

这一切都适用于我使用 php 循环浏览时间表并将行打印到文件中。

问题在于大型数据库可能需要数小时才能运行,这是不可接受的。所以我用 MySQL INTO OUTFILE 命令重写了它,它将运行时间缩短到几秒钟,这很棒。

现在的问题是我似乎无法转义描述字段中的所有换行符等。实际上,用户可以在此处输入任何字符组合,包括回车/换行。

这是我拥有的 MySQL 代码的 sn-p:

SELECT id, 
       client,
       project,
       task,
       REPLACE(REPLACE(ifnull(ts.description,''),'\n',' '),'\r',' ') AS description, 
       time,
       date  
      INTO OUTFILE '/path/to/file.csv'
      FIELDS ESCAPED BY '""'
      TERMINATED BY ',' ENCLOSED BY '"'
      LINES TERMINATED BY '\n'
      FROM ....

但是……

当我尝试查看输出文件的源时,文件中仍然存在换行符,因此 Excel 的 CSV 导入会破坏 Excel 向导创建的所有花哨的宏和数据透视表。

关于最佳行动方案的任何想法?

【问题讨论】:

    标签: mysql sql excel into-outfile


    【解决方案1】:

    我认为你的陈述应该是这样的:

    SELECT id, 
       client,
       project,
       task,
       description, 
       time,
       date  
      INTO OUTFILE '/path/to/file.csv'
      FIELDS TERMINATED BY ',' OPTIONALLY ENCLOSED BY '"'
      LINES TERMINATED BY '\n'
      FROM ts
    

    主要没有FIELDS ESCAPED BY '""' 选项,OPTIONALLY ENCLOSED BY '"' 将在描述字段等方面发挥作用,您的数字将在 Excel 中被视为数字(不是由数字组成的字符串)

    也尝试调用:

    SET NAMES utf8;
    

    在您的输出文件选择之前,这可能有助于内联字符编码(所有 UTF8)

    让我们知道你的进展。

    【讨论】:

    • 是的,这是我现在实际使用的语句,它似乎正在工作。我正在替换 \n 和 , 以防万一。
    • 你是如何使用SET NAMES utf8;的?
    • dayne,使用 SET NAMES utf8;在 SELECT 语句之前作为普通查询(就像查询 SELECT 或 UPDATE 语句一样,即在 mysql 命令行中或通过 PHP 或 Ruby 或....)
    • 如果您遇到文件权限问题,只需像 @Felix Z 那样写入 /tmp 即可解决任何问题。
    • OPTIONALLY 是拼图中缺失的一块! OPTIONALLY ENCLOSED BY '"' ESCAPED BY '"' 为我解决了问题(Windows Office 风格转义)。
    【解决方案2】:

    这里是有效的: 模拟 Excel 2003(另存为 CSV 格式)

    SELECT 
    REPLACE( IFNULL(notes, ''), '\r\n' , '\n' )   AS notes
    FROM sometables
    INTO OUTFILE '/tmp/test.csv' 
    FIELDS TERMINATED BY ',' ENCLOSED BY '"' ESCAPED BY '"'
    LINES TERMINATED BY '\r\n';
    
    1. Excel 将 \r\n 保存为行分隔符。
    2. Excel 为列数据中的换行符保存 \n
    3. 必须先替换数据中的 \r\n 否则 Excel 会认为它是下一行的开始。

    【讨论】:

    • 谢谢!这是这里唯一一个对我有用的
    【解决方案3】:

    如果您尝试以下操作会发生什么?

    尝试使用双 REPLACE 语句,而不是:

    REPLACE(IFNULL(ts.description, ''),'\r\n', '\n')
    

    另外,我认为应该是LINES TERMINATED BY '\r\n' 而不仅仅是'\n'

    【讨论】:

      【解决方案4】:

      在没有实际看到您的输出文件进行确认的情况下,我的猜测是您必须摆脱 FIELDS ESCAPED BY 值。

      MySQL 的 FIELDS ESCAPED BY 可能以两种您不指望的方式表现:(1)它只是一个字符,所以在您的情况下,它可能只等于一个引号; (2) 用于MySQL认为需要转义的每个字符前,包括FIELDS TERMINATED BYLINES TERMINATED BY值。这对大多数计算世界来说都是有意义的,但这不是 Excel 转义的方式。

      我认为您的双 REPLACE 正在工作,并且您成功地用空格替换了文字换行符(在 Windows 样式换行符的情况下为两个空格)。但是,如果您的数据中有任何逗号(文字,而不是字段分隔符),则这些逗号前面都带有引号,Excel 对它的处理与 MySQL 大不相同。如果是这种情况,那么导致 Excel 出错的错误换行符实际上是 MySQL 打算用作行终止符的换行符。

      【讨论】:

        【解决方案5】:

        可能无济于事,但您可以尝试使用该内容创建一个 CSV 表:

        DROP TABLE IF EXISTS foo_export;
        CREATE TABLE foo_export LIKE foo;
        ALTER TABLE foo_export ENGINE=CSV;
        INSERT INTO foo_export SELECT id, 
           client,
           project,
           task,
           REPLACE(REPLACE(ifnull(ts.description,''),'\n',' '),'\r',' ') AS description, 
           time,
           date
          FROM ....
        

        【讨论】:

          【解决方案6】:

          以下过程为我解决了所有转义问题,并使该过程更像一个通用实用程序。

          CREATE PROCEDURE `export_table`(
          IN tab_name varchar(50), 
          IN select_columns varchar(1000),
          IN filename varchar(100),
          IN where_clause varchar(1000),
          IN header_row varchar(2000))
          
          BEGIN
          INSERT INTO impl_log_activities(TABLE_NAME, LOG_MESSAGE,CREATED_TS) values(tab_name, where_clause,sysdate());
          COMMIT;
          SELECT CONCAT( "SELECT ", header_row,
              " UNION ALL ",
              "SELECT ", select_columns, 
              " INTO OUTFILE ", "'",filename,"'"
              " FIELDS TERMINATED BY ',' OPTIONALLY ENCLOSED BY '\"' ESCAPED BY '""' ",
              " LINES TERMINATED BY '\n'"
              " FROM ", tab_name, " ",
              (case when where_clause is null then "" else where_clause end)
          ) INTO @SQL_QUERY;
          
          INSERT INTO impl_log_activities(TABLE_NAME, LOG_MESSAGE,CREATED_TS) values(tab_name, @SQL_QUERY, sysdate());
          COMMIT;
          
          PREPARE stmt FROM @SQL_QUERY;
          EXECUTE stmt;
          DEALLOCATE PREPARE stmt;
          

          结束

          【讨论】:

            猜你喜欢
            • 2017-08-24
            • 2016-08-24
            • 2015-06-20
            • 1970-01-01
            • 2017-07-07
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            相关资源
            最近更新 更多