2

我对SELECT INTO OUFILE有奇怪的行为,但没有找到答案。

要恢复,我有一张这样的桌子:

CREATE TABLE `mytable` (
  `id` int(11) NOT NULL auto_increment,
  `field1` decimal(10,2) default NULL,
  `field2` int(11) default NULL,
  `field3` tinyint(4) default NULL,
  PRIMARY KEY  (`id`),
) ENGINE=MyISAM AUTO_INCREMENT=2 DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci;

当我执行这样的查询时:

SELECT * INTO OUTFILE '/tmp/output.dat' 
FIELDS TERMINATED BY '|' 
OPTIONALLY ENCLOSED BY '\"' 
ESCAPED BY '' 
LINES TERMINATED BY '\n' 
FROM mytable;

我在 output.dat 中得到这样的结果:

"12345678"|"20.00^@^@^@^@^@^@^@"|"1426513906^@"|"0^@^@^@"
"95863214"|"20.00^@^@^@^@^@^@^@"|"1426514075^@"|"1^@^@^@"

没有转义

SELECT * INTO OUTFILE '/tmp/output.dat' 
FIELDS TERMINATED BY '|' 
OPTIONALLY ENCLOSED BY '\"' 
LINES TERMINATED BY '\n' 
FROM mytable;

我有这样的结果:

"12345678"|"20.00\0\0\0\0\0\0\0"|"1426513906\0"|"0\0\0\0"
"95863214"|"20.00\0\0\0\0\0\0\0"|"1426514075\0"|"1\0\0\0"

mysql环境:

"protocol_version";"10"
"version";"5.0.67-community-log"
"version_comment";"MySQL Community Edition (GPL)"
"version_compile_machine";"x86_64"
"version_compile_os";"redhat-linux-gnu"

似乎 mysql 尝试填充这个特殊字符以在 mytble 的结构中设置大小。使用TRIM,我没有这个字符。但我想知道只有整数和小数才有这种行为是正常的还是它的错误?我还想知道是否有另一种解决方案可以避免在每个字段中使用TRIM ?因为我有很多比这个更复杂的查询。

感谢您的帮助以及您阅读我的帖子所花费的时间

问候

编辑:我认为问题可能仅来自INTO OUFILE和类型字段。在这种情况下,我没想到要提到嵌套联合。所以我改变了标题,我正在回答我的问题。

4

1 回答 1

0

最后编辑: 要恢复,找到的最佳解决方案是用反斜杠强制转义,而不是将其留空

SELECT * INTO OUTFILE '/tmp/output1.dat' 
FIELDS TERMINATED BY '|' 
ENCLOSED BY '\"' 
ESCAPED BY '\\'
LINES TERMINATED BY '\n' 
FROM 
    ((SELECT
    id_test,
    field2,
    field3
    FROM mytable1)

    UNION

    (SELECT 
    * 
    FROM 
        ((SELECT
        id_test,
        field2,
        NULL AS field3
        FROM mytable2)

        UNION

        (SELECT
        id_test,
        NULL AS field2,
        NULL AS field3
        FROM mytable3)
        ) test)
    ) tmptable;

mysql文档中的注释:

如果 FIELDS ESCAPED BY 字符为空,则不转义任何字符,并且 NULL 输出为 NULL,而不是 \N。指定空转义字符可能不是一个好主意,尤其是当数据中的字段值包含刚刚给出的列表中的任何字符时。

……

另请注意,如果您指定一个空的 ESCAPED BY 值,则可能会无意中生成 LOAD DATA INFILE 无法正确读取的输出。

以前的解决方案有解释:

我找到了我的问题的答案。它来自具有 NULL 值的嵌套联合。我会用例子来解释它比长篇大论更好。

这里是mysql上下文:

DROP TABLE IF EXISTS `mytable1`;

CREATE TABLE `mytable1` (
  `id_test` INT(11) NOT NULL AUTO_INCREMENT,
  `field1` DECIMAL(10,2) DEFAULT NULL,
  `field2` INT(11) DEFAULT NULL,
  `field3` TINYINT(4) DEFAULT NULL,
  PRIMARY KEY  (`id_test`)
) ENGINE=MYISAM AUTO_INCREMENT=95863215 DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci;

/*Data for the table `mytable` */

INSERT  INTO `mytable1`(`id_test`,`field1`,`field2`,`field3`) VALUES (12345678,20.00,1426513906,0),(95863214,20.00,1426514075,1);

/*Table structure for table `mytable2` */

DROP TABLE IF EXISTS `mytable2`;

CREATE TABLE `mytable2` (
  `id_test` INT(11) NOT NULL AUTO_INCREMENT,
  `field1` DECIMAL(10,2) DEFAULT NULL,
  `field2` INT(11) DEFAULT NULL,
  PRIMARY KEY  (`id_test`)
) ENGINE=MYISAM AUTO_INCREMENT=3 DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci;

/*Data for the table `mytable2` */

INSERT  INTO `mytable2`(`id_test`,`field1`,`field2`) VALUES (1,25.00,12345),(2,11.00,52146);

/*Table structure for table `mytable3` */

DROP TABLE IF EXISTS `mytable3`;

CREATE TABLE `mytable3` (
  `id_test` INT(11) NOT NULL AUTO_INCREMENT,
  `field1` DECIMAL(10,2) DEFAULT NULL,
  `field3` TINYINT(4) DEFAULT NULL,
  PRIMARY KEY  (`id_test`)
) ENGINE=MYISAM AUTO_INCREMENT=5 DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci;

/*Data for the table `mytable3` */

INSERT  INTO `mytable3`(`id_test`,`field1`,`field3`) VALUES (2,12.00,2),(4,23.00,31);

并与环境:

"protocol_version";"10"
"version";"5.0.67-community-log"
"version_comment";"MySQL Community Edition (GPL)"
"version_compile_machine";"x86_64"
"version_compile_os";"redhat-linux-gnu"

或者用这个:

"protocol_version";"10"
"version";"5.0.95-log"
"version_bdb";"Sleepycat Software: Berkeley DB 4.1.24: (December 16, 2011)"
"version_comment";"Source distribution"
"version_compile_machine";"x86_64"
"version_compile_os";"redhat-linux-gnu"

我们用这种查询重现这个案例:

SELECT * INTO OUTFILE '/tmp/output1.dat' 
FIELDS TERMINATED BY '|' 
ENCLOSED BY '\"' 
ESCAPED BY ''
LINES TERMINATED BY '\n' 
FROM 
    ((SELECT
    id_test,
    field2,
    field3
    FROM mytable1)

    UNION

    (SELECT 
    * 
    FROM 
        ((SELECT
        id_test,
        field2,
        NULL AS field3
        FROM mytable2)

        UNION

        (SELECT
        id_test,
        NULL AS field2,
        NULL AS field3
        FROM mytable3)
        ) test)
    ) tmptable;

我们得到这个结果:

"12345678"|"1426513906"|"0^@^@^@"
"95863214"|"1426514075"|"1^@^@^@"
"1"|"12345"|NULL
"2"|"52146"|NULL
"2"|NULL|NULL
"4"|NULL|NULL

例如,当我们用 1 替换最后一个 NULL 或删除最后一个 union 来执行相同的查询时:

SELECT * INTO OUTFILE '/tmp/output1.dat' 
FIELDS TERMINATED BY '|' 
ENCLOSED BY '\"' 
ESCAPED BY ''
LINES TERMINATED BY '\n' 
FROM 
    ((SELECT
    id_test,
    field2,
    field3
    FROM mytable1)

    UNION

    (SELECT 
    * 
    FROM 
        ((SELECT
        id_test,
        field2,
        NULL AS field3
        FROM mytable2)

        UNION

        (SELECT
        id_test,
        NULL AS field2,
        1 AS field3
        FROM mytable3)
        ) test)
    ) tmptable;

我们得到了预期的正确结果:

"12345678"|"1426513906"|"0"
"95863214"|"1426514075"|"1"
"1"|"12345"|NULL
"2"|"52146"|NULL
"2"|NULL|1
"4"|NULL|1

这只是一个简单的例子,没有在哪里解释。在我的例子中,使用嵌套联合是因为我们在不同的条件下有不同的值。

因此,在使用INTO OUTFILE导出的情况下,请小心使用具有NULL值的嵌套UNION。就我而言,解决方案是在一个没有UNION的查询中使用熔断器嵌套联合。

请注意,我没有在 Windows 7 上使用 Mysql 5.6.23 MySQL Community Server 重现此案例。

于 2015-03-27T16:18:16.037 回答