为什么CONCAT()不默认为MySQL中的默认字符集?

w.k*_*w.k 13 mysql perl utf-8

是什么原因,在纯UTF-8环境中使用CONCAT()MySQL仍然将连接字符串(当表达式中的某些col为例如int或date)视为其他字符集(可能是Latin-1)?

从client(\s)看到的MySQL环境:

Server characterset:    utf8
Db     characterset:    utf8
Client characterset:    utf8
Conn.  characterset:    utf8
Run Code Online (Sandbox Code Playgroud)

测试数据集:

CREATE TABLE `utf8_test` ( 
    `id` int(10) unsigned NOT NULL auto_increment, 
    `title` varchar(50) collate utf8_estonian_ci default NULL,
    `year` smallint(4) unsigned NOT NULL default '0', 
    PRIMARY KEY  (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_estonian_ci;

INSERT INTO utf8_test VALUES (1, 'Õäöüšž', 2011);
Run Code Online (Sandbox Code Playgroud)

这个查询很好:

SELECT id, title FROM utf8_test;
Run Code Online (Sandbox Code Playgroud)

这个关闭utf-8标志(已经在MySQL,AFIU):

SELECT CONCAT(id, title) FROM utf8_test;
Run Code Online (Sandbox Code Playgroud)

从mysql-client看来一切都很好,因为它设置为将字符显示为UTF-8,但是当通过perl DBI运行时,所有内部有CONCAT()的查询结果都没有设置utf-8标志.示例代码:

#!/usr/bin/perl

use strict;
use utf8::all;
use Encode qw(is_utf8);

my $dbh = your_db_connect_routine('test');

my $str = $dbh->selectrow_array('SELECT CONCAT(id, title) FROM utf8_test');
print "CONCAT: False\n" unless ( is_utf8($str) );

my $str = $dbh->selectrow_array('SELECT title FROM utf8_test');
print "NO CONCAT: False\n" unless ( is_utf8($str) );
Run Code Online (Sandbox Code Playgroud)

我知道至少有两种解决方法

  • 用CAST()查询 SELECT CONCAT( CAST(id AS CHAR CHARACTER SET utf8), title) FROM utf8_test
  • 使用$str = Encode::_utf8_on($str)(被认为是不好的做法?)

但我在问:为什么它在MySQL中呢?我应该将其视为错误或功能吗?

Elj*_*kim 20

这是MySQL中一个众所周知的错误.它已在MySQL 5.5中修复

请参阅:http://bugs.mysql.com/bug.php?id = 12030

问题源于将整数与varchar连接起来.

解决方法是首先将id(整数)转换为char,然后连接,即:

SELECT CONCAT(cast(id as char), title) FROM utf8_test
Run Code Online (Sandbox Code Playgroud)

  • 不仅整数,而且时间戳导致问题.谢谢你的解决方法!+1 (2认同)