mysql CONVERT()和CAST()到整数将值增加1

时间:2016-05-17 15:39:45

标签: mysql casting

我正在尝试从电话呼叫表中选择记录,其中名为Call_Rating的ENUM字符串字段的值小于整数值4. Call_Rating字段只能包含值'0', '1', '2', '3', '4', '5'。每当我使用CONVERT(Call_Rating, UNSIGNED INTEGER)CAST(Call_Rating AS UNSIGNED)时,Call_Rating字段的值都会增加1.为什么它会这样做并且除了手动从中减去1之外还有其它方法可以避免它CALL()或CAST()函数? 此外,这是一个由其他人设置并且仍在各种系统中使用的旧数据库,因此在不更改数据库架构的情况下解决此问题的一些方法将非常有用。

创建表

CREATE TABLE `member_calls` (
  `CallID` int(10) NOT NULL AUTO_INCREMENT,
  `Call_Rating` enum('0','1','2','3','4','5') CHARACTER SET latin1 NOT NULL DEFAULT '0',
  PRIMARY KEY (`CallID`)
) ENGINE=MyISAM AUTO_INCREMENT=538616 DEFAULT CHARSET=utf8;

表中的数据

INSERT INTO `member_calls`
  (`CallID`, `Call_Rating`)
VALUES
  (510515, '4'),
  (510909, '0'),
  (538614, '3'),
  (538615, '5');

选择声明

SELECT `CallID`, `Call_Rating`, CAST(`Call_Rating` AS UNSIGNED) AS 'Casted', CONVERT(`Call_Rating`, UNSIGNED INTEGER) AS 'Converted'
FROM `member_calls`
WHERE CONVERT(`Call_Rating`, SIGNED INTEGER) < 4
   OR CAST(`Call_Rating` AS UNSIGNED) < 4;

给出结果

CallID  Call_Rating Casted  Converted
510909  0           1       1

预期结果

CallID  Call_Rating Casted  Converted
510909  0           0       0
538614  3           3       3

编辑2016-5-17

感谢大家的意见。我现在明白为什么这个问题正在发生。基本上,ENUM被视为一个数组,CAST()/ CONVERT()返回数组的索引而不是值。对此最好的解决方案是将ENUM更改为INT字段,但这在我的情况下是不可取的,因为DB正在实时使用,并且更改数据类型可能会导致其他地方出现问题。因此,lserni的解决方案对我来说最有用。

3 个答案:

答案 0 :(得分:3)

将ENUM直接转换为INTEGER会产生该ENUM的索引,并且由于它们从1开始,因此第一个元素为0并变为1,等等。

它根本没有增加1 :它正在返回一个整数值,这似乎是因为它是正确的值加1 < / strong>即可。但它可能是其他任何东西。如果你有一个&#39; 1&#39;,&#39; 2&#39;&#39; 3&#39;,&#39; 4&#39;,&#39; 5&#39; ,如果没有&#39; 0&#39;,那么出现的结果是正确的,即使它确实不是。

运行从CHAR传递的双转换,或转换为CHAR后再次隐式转换:

SELECT CONVERT(CONVERT(Call_Rating, CHAR(1)), UNSIGNED), 0+CONVERT(Call_Rating, CHAR(1)), 0+Call_Rating, CAST(Call_Rating AS UNSIGNED) from member_calls;


+--------------------------------------------------+---------------------------------+---------------+-------------------------------+
| CONVERT(CONVERT(Call_Rating, CHAR(1)), UNSIGNED) | 0+CONVERT(Call_Rating, CHAR(1)) | 0+Call_Rating | CAST(Call_Rating AS UNSIGNED) |
+--------------------------------------------------+---------------------------------+---------------+-------------------------------+
|                                                2 |                               2 |             3 |                             3 |
+--------------------------------------------------+---------------------------------+---------------+-------------------------------+

答案 1 :(得分:2)

我不能详细解释这里发生的事情,但这可能与你使用带有数值的ENUM而不是INT类型这一事实有关,这似乎是理智的选择。

mySQL手册strongly recommends against this:

  

我们强烈建议您不要将数字用作枚举值,因为它不会通过适当的TINYINT或SMALLINT类型保存在存储上,并且很容易混淆字符串和基础数字值(可能不是如果你不正确地引用ENUM值。如果确实使用数字作为枚举值,请始终将其括在引号中。如果省略引号,则将该数字视为索引。请参阅枚举文字的处理,以查看引用的数字是否可能被错误地用作数字索引值。

mySQL可能正在使用数字索引而不是ENUM值,这会导致奇怪。

只需切换到正确的INT字段。

答案 2 :(得分:1)

你应该得到ENUM不是枚举的字符串或整数。

对我来说,这是你应该尽可能避免在DB中使用的类型。

这是小提琴,说明为什么会发生这种情况:

http://sqlfiddle.com/#!9/de53b2/1

正如你可以看到mysql将ENUM转换为int时 - 返回类似于array(enum)中保存值的索引但不是返回int的值。

但是为了说明mysql的功能,您可以运行此查询以获得预期的结果:

http://sqlfiddle.com/#!9/e2cf5/3

SELECT `CallID`, `Call_Rating`,
  ELT(CAST(`Call_Rating` AS UNSIGNED),'0','1','2','3','4','5') AS 'Casted', 
  ELT(CONVERT(`Call_Rating`, SIGNED INTEGER),'0','1','2','3','4','5') AS 'Converted'
FROM `member_calls`
HAVING `Casted` < 4
   OR `Converted` < 4;

但无论如何这不是最佳解决方案。 我认为你应该更好地重新设计你的数据库架构。