为什么TINYINT(1)可以作为布尔值使用,而INT(1)不能?

15
为什么 TINYINT(1) 可以作为布尔值使用?按照我所理解的官方文档,(1)应该是指显示宽度为1,因此如果我在其中存储 56,我认为它应该打印出 5。但是由于某种原因,它总是打印出 1 或者 0
另外一个情况是,如果我在 INT(1) 中存储56,那么它会打印出 56(至少在SQLFiddle上是这样)。这是怎么回事呢?

请参见https://dev59.com/dG865IYBdhLWcg3wkPaD#3751882。 - Pavel Strakhov
5个回答

23

MySQL整数类型括号中的数字(1)与数据类型接受的值的范围或存储方式无关,仅用于显示。

请参阅我的答案:Types in MySQL: BigInt(20) vs Int(20) etc

TINYINT与TINYINT(1)、TINYINT(2)或TINYINT(64)没有任何区别。它是一个8位带符号整数数据类型,并且可以接受从-128到127的任何8位整数值。

mysql> create table b (i tinyint(1));

mysql> insert into b values (42);

mysql> select * from b;
+------+
| i    |
+------+
|   42 |
+------+

为了方便起见,MySQL支持BOOL的别名,该别名立即被TINYINT(1)替换。

mysql> create table b2 (i bool);

mysql> show create table b2;

CREATE TABLE `b2` (
  `i` tinyint(1) DEFAULT NULL
) ENGINE=InnoDB DEFAULT CHARSET=latin1

正如我之前所说,使用(1)几乎没有任何意义,它只是一个惯例,因此如果您看到TINYINT(1),合理地假设该列旨在用作布尔值。但是MySQL中没有任何限制阻止您在其中存储其他整数值。

如果您希望列仅接受0或1,则可以使用BIT(1):

mysql> create table b3 (i bit(1));

mysql> insert into b3 values (0), (1);
Query OK, 2 rows affected (0.00 sec)
Records: 2  Duplicates: 0  Warnings: 0

mysql> insert into b3 values (-1);
ERROR 1406 (22001): Data too long for column 'i' at row 1

mysql> insert into b3 values (2);
ERROR 1406 (22001): Data too long for column 'i' at row 1

然而,与TINYINT相比,这并没有节省任何空间,因为给定列的存储会舍入到最近的字节。

附注:尽管@samdy1的回答如此,但TINYINT并不存储字符串'0'或'1',它存储整数0或1,以及从-128到127的其他整数。在SQL中不需要引用整数,我经常感到困惑为什么许多开发人员会这样做。


这是哪个版本的MySQL?这不是由OP报告、在本问答其他地方链接的SQLfiddle或ypercube的答案所报道的行为... - pilcrow
这些代码示例是从在MySQL 5.5.31上运行它们复制的。实际上,这是Percona Server,但在Percona Server中没有数据类型处理方面的区别。 - Bill Karwin
我的本地实例(MySQL 5.5,而不是Percona)与您的发现相符。我正在按照您的思路撰写答案,然后进行测试,对Fiddle中的这些结果感到非常惊讶。 - ypercubeᵀᴹ
JakeFeasel已经回复(在the Heap)这与JBDC有关。 - ypercubeᵀᴹ
好的,我刚刚测试了MySQL Connector/J 5.1.22,它在INSERT或SELECT时不会进行任何布尔转换。我不知道Jake正在使用哪个JDBC驱动程序。 - Bill Karwin

9

TINYINT列可以存储从-128127的数字。

TINYINT(1)有点奇怪。它可能是因为它被认为是BOOLEAN数据类型,所以在某些情况下只返回01,同时仍保留存储的(-128到127)值。

(更正: 我只在SQL-Fiddle中看到了这种奇怪的行为,而在本地访问MySQL时没有看到,所以它可能是SQL-Fiddle的怪异性,可能与BOOLEAN的等效性有关),而不是MySQL的问题。

请参见SQL-Fiddle

CREATE TABLE test
( i TINYINT(1)
) ;

INSERT INTO test 
  (i)
VALUES
  (0),  (1), (6), (120), (-1) ;

我们在哪里获取(仅限于SQL-Fiddle,否则无法访问MySQL!):
SELECT i
FROM test ;

  i
-----
  0
  1
  1
  1
  1

但是:

SELECT CAST(i AS SIGNED) i2
FROM test ;

  i2
-----
   0
   1
   6
 120
  -1

你知道这个有没有文档记录吗?当前关于BOOL、TINYINT([M])和anyINT([M])的文档非常强烈地暗示了OP所期望的行为。 - pilcrow
我在SQLfiddle上看到这个可以工作,但是我无法在我的MySQL 5.5.31实例中复制它。你知道让tinyint(1)以这种方式行为需要什么吗?也许是SQL模式? - Bill Karwin
@pilcrow,BillKarwin:实际上我也不知道。也许这是SQL-Fiddle的特殊性,而不是MySQL的问题。 - ypercubeᵀᴹ

8

3

0
据我理解,TINYINT(1)只能容纳'0''1'(根据我的经验)。因此,可以假设'0''1'被翻译成truefalse

1
不完全正确:http://www.sqlfiddle.com/#!2/0dc1d/5 它只显示为1,实际上并没有存储1。 - user743382
哦,好的,那它仍然返回true吗? - notquiteamonad
嗯,有点混乱,问题在于它不会返回false(0),而任何不是false(0)的东西都被视为true,但不一定等于true(1)。http://www.sqlfiddle.com/#!2/0dc1d/11。请参阅[文档](https://dev.mysql.com/doc/refman/5.0/en/numeric-type-overview.html),那里的示例是相关的。 - user743382

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接