用于存储布尔值的MySQL数据类型

Which MySQL data type to use for storing boolean values

提问人: 提问时间:11/14/2008 最后编辑:Peter Mortensen 更新时间:7/13/2021 访问量:1036318

问:

由于MySQL似乎没有任何“布尔”数据类型,那么您在MySQL中“滥用”哪种数据类型来存储真/假信息?

特别是在编写和读取 PHP 脚本的上下文中。

随着时间的流逝,我使用并看到了几种方法:

  • tinyint、varchar 字段包含值 0/1,
  • 包含字符串 '0'/'1' 或 'true'/'false' 的 varchar 字段
  • 最后是包含两个选项“true”/“false”的枚举字段。

以上似乎都不是最佳选择。我倾向于使用 tinyint 0/1 变体,因为 PHP 中的自动类型转换非常简单地给了我布尔值。

那么你使用哪种数据类型呢?有没有我忽略的为布尔值设计的类型?您认为使用一种或另一种类型有什么优点/缺点吗?

mysql 布尔值 sqldatatypes

评论

242赞 smp7d 2/29/2012
任何正在阅读这个问题的旧答案的人都需要了解MySQL在版本5中添加了位数据类型。尽可能使用该信息。dev.mysql.com/doc/refman/5.0/en/bit-type.html
3赞 tereško 7/26/2012
MySQL中许多布尔值的替代相关的问题?
8赞 DevT 8/29/2012
对于当前版本的 MYSQL 布尔类型可用 - dev.mysql.com/doc/refman/5.5/en/numeric-type-overview.html 检查此项。根据该值,零被认为是假的
9赞 Cees Timmerman 2/18/2014
bit(1)有点**在Excel中导入。切换到工作。tinyint(1)
8赞 V-SHY 3/14/2014
现在我们在 5 年后有了布尔值

答:

22赞 Fred 11/14/2008 #1

我使用 TINYINT(1) 在 Mysql 中存储布尔值。

我不知道使用这个有什么好处......但是如果我没记错的话,mysql 可以存储布尔值 (BOOL) 并将其存储为 tinyint(1)

http://dev.mysql.com/doc/refman/5.0/en/other-vendor-data-types.html

1370赞 markus 11/14/2008 #2

对于 MySQL 5.0.3 及更高版本,您可以使用 .手册说:BIT

从 MySQL 5.0.3 开始,BIT 数据类型用于存储位字段 值。BIT(M) 类型支持存储 M 位值。M 级范围 从 1 增加到 64

否则,根据 MySQL 手册,您可以使用 或 ,它们目前是 tinyint(1) 的别名:BOOLBOOLEAN

Bool、Boolean:这些类型是 TINYINT(1) 的同义词。值 零被视为 false。非零 值被视为 true。

MySQL还指出:

我们打算实现完整的布尔值 类型处理,根据 标准 SQL,在未来的 MySQL 中 释放。

参考资料: http://dev.mysql.com/doc/refman/5.5/en/numeric-type-overview.html

评论

13赞 Roland Bouman 5/16/2010
是的,我会选择这个或 CHAR(1) 并存储“Y”/“N”或“T”/“F”等,具体取决于上下文。使用小整数类型的优点是,您可以在 RDBMS 之间获得最大的可移植性
47赞 Mild Fuzz 6/2/2011
至少在 PHP 中,使用 char 将导致更多的代码,因为如果不进一步处理,将永远无法正确计算。!$boolean
0赞 mercury 3/17/2022
解决方案是将 Laravel 模型中的列$casts为布尔值,类似受保护的$casts = [ 'shipped' => 'boolean', 'refund' => 'boolean', ];
0赞 Oliver Bock 2/10/2023
BIT 在 node.js + mysql 中很烦人,因为它作为缓冲区返回,这总是真实的。
1赞 SandPiper 6/26/2023
引用链接已损坏。
293赞 Philip Morton 11/14/2008 #3

BOOL并且是 的同义词。零是,其他任何东西都是。更多信息请点击此处BOOLEANTINYINT(1)falsetrue

评论

7赞 JamesHalsall 3/20/2014
它只不过是确定值的显示方式,如果你知道存储大小,那么你想改用(1)BIT
43赞 spencer7593 7/10/2014
@JamesHalsall:实际上,两者都会使用一个字节的存储。直到 MySQL 5.0.3 之前,实际上是 的同义词。MySQL的更高版本更改了BIT的实现。但是,即使实现了更改,数据类型仍然没有“存储大小”的好处(至少对于InnoDB和MyISAM;其他存储引擎,例如NDB可能对多个BIT列声明进行了一些存储优化。更大的问题是,某些客户端库无法识别或正确处理返回的数据类型列。A 效果更好。BIT(1)TINYINT(1)BITTINYINTBITBITTINYINT
5赞 Walter 1/23/2015
MySQL 5.0 手册明确指出布尔值为 1 或 0。“其他任何东西都是”这句话是不正确的。true
7赞 spencer7593 4/25/2015
@Walter:确实是这样,只是有些缺乏解释。简而言之,在布尔上下文中,表达式的计算结果可以为 NULL、FALSE 或 TRUE。在MySQL语句中,在布尔上下文中计算的表达式首先被计算为整数(十进制和浮点值四舍五入,字符串以MySQL将字符串转换为整数的通常古怪方式进行转换)。NULL 显然是 NULL(既不是 TRUE 也不是 FALSE)。整数值 0 的计算结果为 FALSE,任何其他整数值(1、2、-7 等)的计算结果为 TRUE。为了兼容,我们模仿了 TINYINT 布尔值的逻辑/处理
6赞 spencer7593 4/25/2015
@Walter:这很容易测试,例如。表达式 -7 在布尔上下文中计算,查询返回一行。我们可以用 0 或任何计算结果为整数值 0 的表达式进行测试,并且不返回任何行。如果 WHERE 子句中的表达式的计算结果为除零以外的任何非 null 整数值,则表达式为 TRUE。(我相信十进制和浮点值会“四舍五入”为整数,例如 计算结果为 。我们得到与 相同的结果,因为字符串的计算结果也为整数值 0。SELECT 'foo' AS bar FROM dual WHERE -7WHERE 1/3WHERE 0WHERE 'foo''foo'
35赞 Ciaran McNulty 11/14/2008 #4

如果使用 BOOLEAN 类型,则将其别名为 TINYINT(1)。如果您想使用标准化的 SQL,并且不介意该字段可能包含超出范围的值(基本上任何不是 0 的值都将是“true”),这是最好的选择。

ENUM('False', 'True') 将允许您在 SQL 中使用字符串,MySQL 会根据指定枚举的顺序在内部将字段存储为整数,其中 'False'=0 和 'True'=1。

在 MySQL 5+ 中,您可以使用 BIT(1) 字段来指示 1 位数字类型。我不认为这实际上会占用更少的存储空间,但再次允许您将可能的值限制为 1 或 0。

以上所有存储都将使用大致相同的存储量,因此最好选择您认为最容易使用的存储空间。

评论

8赞 Roland Bouman 5/16/2010
您关于 ENUM 的评论不正确:尝试 CAST(yourenumcol AS UNSIGNED),您会注意到 False 将为 1,True 将为 2。ENUM 的另一个问题是插入 '' (空字符串) 太容易了。我不建议使用它。
5赞 M-Peror 7/21/2011
根据我的经验,从 PHP 代码中使用 BIT(1) 字段有点麻烦。TINYINT(1) 要容易得多,并且生成的代码可读性更强。
1赞 BMiner 12/7/2011
@M-Peror - “使用 PHP 代码中的 BIT(1) 字段有点麻烦”......没有双关语的意思。:)但是,是的,我同意。我记得 TINYINT(1) 也更容易......只是不记得为什么。还有人对此有想法吗?BIT(1) 从表面上看似乎更好,因为您可以限制为 0 或 1。我认为BIT有时被解释为二进制数据(取决于编程语言和驱动程序/库);而 TINYINT 更像是一个数字。
2赞 M-Peror 12/21/2011
@BMiner——哈哈,真是无意的,没注意到:)但事实上,如果我没记错的话,位字段被解释为二进制的东西,而 tinyint 更容易被视为数字,因此更容易在(布尔)表达式中使用。
40赞 Josh 5/1/2009 #5

这个问题已经得到回答,但我想我会投入 0.02 美元。 我经常使用 , 其中 .CHAR(0)'' == true and NULL == false

来自 MySQL 文档

CHAR(0)当你需要一个只能接受的柱子时,也相当不错 两个值:定义为仅占用一个值的列 位,并且只能接受值和(空字符串)。CHAR(0)NULLNULL''

评论

24赞 Roland Bouman 5/16/2010
嗯,如果你是我,这似乎是自找麻烦。我的意思是,根据语言的不同,可能很容易发现 NULL 和 '' 之间的差异(例如 PHP)。
5赞 spencer7593 6/10/2015
在节省空间(用于表示布尔值的字节数)方面,这种方法显然是赢家。这比 TINYINT 节省了一个字节。缺点(正如一些评论所指出的)是某些客户端可能难以区分 NULL 和空字符串。甚至一些关系数据库(例如 Oracle)也不区分零长度字符串和 NULL。
11赞 CJ Dennis 5/15/2018
这是非常聪明的!我曾经写过聪明的代码,现在我像躲避瘟疫一样避免它。我现在希望我的代码具有清晰的意图,而不仅仅是正确的行为。我的建议?仅当您想混淆任何必须支持代码/数据库的人时,才这样做。例如,在 PHP 中,both 和 都是虚假值。''null
3赞 prograhammer 1/31/2019
@CJDennis 如果您已将数据库层抽象在存储库模式后面,则不必担心此解决方案的模糊性。
12赞 Jonathan 7/14/2011 #6

在MySQL实现位数据类型之前,如果您的处理确实需要空间和/或时间,例如大容量事务,请创建一个为所有布尔变量调用的TINYINT字段,并在SQL查询中屏蔽和移动所需的布尔位。bit_flags

例如,如果最左边的位代表布尔值字段,而最右边的 7 位表示什么都没有,那么你的字段将等于 128(二进制 10000000)。屏蔽(隐藏)最右边的 7 位(使用按位运算符),并将第 8 位向右移动 7 个空格,最终得到 00000001。现在,整个数字(在本例中为 1)就是您的值。bit_flags&

SELECT (t.bit_flags & 128) >> 7 AS myBool FROM myTable t;

if bit_flags = 128 ==> 1 (true)
if bit_flags = 0 ==> 0 (false)

您可以在测试时运行如下语句

SELECT (128 & 128) >> 7;

SELECT (0 & 128) >> 7;

等。

由于您有 8 位,因此您可能有一个字节的 8 个布尔变量。一些未来的程序员总是会使用接下来的七位,所以你必须屏蔽。不要只是转移,否则你将来会为自己和他人创造地狱。确保你让MySQL进行掩码和移位——这将比让Web脚本语言(PHP、ASP等)快得多。此外,请确保在字段的 MySQL 注释字段中放置注释。bit_flags

在实现此方法时,您会发现这些网站很有用:

评论

7赞 yep 7/16/2011
这似乎只是一种混淆未来程序员意图的可怕方式。当然,节省 7 个字节似乎很麻烦(假设您在该表中使用了所有 8 个布尔值!
0赞 CPHPython 5/9/2018
@yep完全没有混淆!编写文档MySQL注释来解释表中的每个字段(如答案所述)!建议的MySQL揭开策略看起来很可靠,并且仅用几列存储多达16个不同的布尔字段比使用16个不同的布尔字段要好。如果使用位操作太令人困惑,并且您更喜欢使用 Web 脚本语言来获取每个布尔值,只需将其存储为 a 并在代码中执行解屏蔽过程(您也不需要将其限制为 8 个字段)...VARCHAR
0赞 dolmen 11/6/2019
类型存在。查看 dev.mysql.com/doc/refman/8.0/en/bit-type.htmlBIT
19赞 Thor 1/13/2012 #7

仅当您有很多布尔字段时,Bit 才比各种字节选项(tinyint、enum、char(1))更有优势。一个位字段仍然占用一个完整的字节。两个位字段适合同一个字节。三、四、五、六、七、八。之后,他们开始填充下一个字节。最终,节省的成本非常小,您应该关注数千项其他优化。除非您正在处理大量数据,否则这几个字节加起来不会太多。如果你在PHP中使用bit,你需要对进出的值进行类型转换。

评论

1赞 Will B. 1/17/2014
+1 表示类型转换注释。除此之外,在使用编程语言时,避免使用惰性编程技术,以支持一致性。使用相同的运算符,而不仅仅是等于。在 PHP 中,if( $var == “” ) 对于 0、false、null、undefined 和 “”将为 true。要测试所有值,通常最好使用 if( true === empty( $var ) ),因为它也可以避免未定义的错误。您还应该验证您正在使用的数据类型 if( is_int( $var ) && $var === 0 ) 或对其进行类型转换以强制其成为任务的特定数据类型 (int) $var。
0赞 Zack Jannsen 2/3/2016
@Thor MySQL与MSSQL一样正确吗?我正在将一个尚未投入生产的新应用程序从MSSQL迁移到MySQL。我没有使用 PHP,而是将 C# 转换为 Java 8。鉴于 Java 是一种强类型语言,我不担心类型处理......只是所有位标志,这些标志将从最多 8 个标志的一个字节移动到给定 TINYINT(1) 的每个标志 1 个字节。您知道有关MySQL此主题的任何文档吗?
1赞 Zack Jannsen 2/3/2016
@Thor 做一些更深入的研究,很清楚答案应该是什么。变化确实发生了,我们已经看到了这种处理方式的改进。了解您的语言将出现在应用层/数据访问层中,并了解您的库支持。我目前使用的是 Java,目前 BIT(1) 是 Hybernate 和 JDBC 等库的推荐选择。以下是 URL [见表 5.2]:dev.mysql.com/doc/connector-j/en/...
0赞 assensi 12/31/2020
使用资源链接证明 8 位 (1) 列采用相同的字节...我找了一段时间,却无处可寻......
80赞 R. S. 2/11/2012 #8

这是一个优雅的解决方案,我非常欣赏,因为它使用零数据字节:

some_flag CHAR(0) DEFAULT NULL

要将其设置为 true,请设置,并将其设置为 false,请设置 。some_flag = ''some_flag = NULL

然后,要测试 true,请检查是否some_flag,要测试 false,请检查 some_flag 。IS NOT NULLIS NULL

(Jon Warren Lentz、Baron Schwartz 和 Arjen Lentz 的“High Performance MySQL: Optimization, Backups, Replication, and More”中对此方法进行了介绍。

评论

3赞 zamnuts 8/14/2012
花哨的把戏!如果使用 MySQL <5 甚至可能比 BIT 更轻,这会很有帮助,但是为了遵守约定和略微减少计算开销(逻辑与精确值),我会说 BIT 是更好的方法。
78赞 Richthofen 4/3/2013
可能“很快”,但它混淆了数据,以至于任何新开发人员都不知道该列代表什么。
6赞 ITS Alaska 4/26/2013
它使用的字节数与 BIT(1) 相同
36赞 Craig Labenz 8/4/2013
祝你好运,让ORM很好地映射到这个。
6赞 eggyal 3/21/2015
我同意@Richthofen的观点,并且很难想象我会提倡使用这种解决方案的情况。但是,如果要使用它,则在列的定义中指定为 a,表示 false 和指示 true,可能会对帮助将来的理解起到很小的作用。COMMENTNULL''
12赞 Geoff Kendall 7/10/2012 #9

我厌倦了试图在 PHP、MySql 和 POST 值的循环中准确地获得零、NULLS 和 '',所以我只使用'Yes'和'No'。

这完美无缺,不需要特殊处理,既不明显也不容易做到。

评论

20赞 ILikeTacos 9/19/2013
如果你真的想浪费这么多空间并牺牲性能,你至少可以用 Y 和 N 选项来完成 CHAR(1)。
4赞 Geoff Kendall 8/6/2014
在大多数现实世界中,“不”和仅仅没有信息之间存在真正的区别。例如,如果用户实际上还没有说“不”,您可能希望默认勾选一个复选框。您认为您究竟节省了多少空间,以及每次需要区分 false 和 NULL 时要进行多少处理 - 如果您确实可以区分的话?在存储图像和数字视频的世界中,节省空间的一两点是完全无关紧要的,但清晰度和减少的处理是真实的。
8赞 Brad 9/30/2014
这个答案没有错,因为它会起作用,而且并不像人们认为的那么糟糕。对于大多数项目(即:工作台大小< 1mil 行),所提供的解决方案之间的性能差异是可以忽略的。如果我的查询在 7 毫秒和 5 毫秒内返回,我不会抱怨......不过,公平地说,如果您的桌子增长到 10mil 行或更多,这可能不是首选解决方案。
1赞 Vlado 10/14/2014
+1 来自我使用 ENUM 数据类型。我个人更喜欢这种表示法:ENUM('y','n')。它结构紧凑(只有一个字节长)、直观且美观,是所有布尔标志的应用程序级约定。您可以直接将其用于 HTML 表单字段。例如,对于 PHP: <select name=“production”> <option value=“y”<?=$production === 'y'?' selected=“selected”' : ''?>>是</option> <option value=“n”<?=$production === 'n'?' selected=“selected”' : ''?>>否</option> </select>
3赞 Madmenyo 9/12/2015
哈哈,这让我眼花缭乱,但我不得不说@GeoffKendall是对的。在很多情况下,不需要最佳性能,无论哪种方法都能为您完成工作,这都是正确的方法。
7赞 Vidz 2/23/2015 #10

参考 Mysql 中的这个链接布尔数据类型,根据应用程序的使用情况,如果只想存储 0 或 1,bit(1) 是更好的选择。

评论

7赞 spencer7593 4/25/2015
确实,这只允许存储 or 值。数据类型的最大问题是各种客户端库对数据类型的处理方式各不相同。查看各种 SQL 工具(SQLyog、TOAD for MySQL、SQL Developer)、“逆向工程”数据库模型的工具以及各种客户端(如 JDBC、PHP、Perl DBI)中的行为,并测试一些 ORM 框架(Hibernate、Mybatis、JPA)。在易用性方面,工具/框架兼容性/原生支持显然是赢家。BIT(1)b'0'b'1'BITTINYINT(1)
1赞 Vidz 4/28/2015
是的。它的完成取决于为应用考虑的框架。例如,PHP 的 Phalcon 框架不处理 Bit 数据类型
0赞 Lucky 12/31/2015
郑重声明,MyBatis 同时支持 和 。参考 MyBatis 的 JdbcType 类,mybatis.org/mybatis-3/apidocs/reference/org/apache/ibatis/type/...BITTINYINT
1赞 Zack Jannsen 2/3/2016
@Vidz 我给你加一提到 BIT(1),但也要向阅读本文的开发人员指出 - 了解您的语言将在应用层/数据访问层中,并了解您的库支持。我目前使用的是 Java,目前 BIT(1) 是 Hybernate 和 JDBC 等库的推荐选择。以下是 URL [见表 5.2]:dev.mysql.com/doc/connector-j/en/...
5赞 Lemures 6/26/2018 #11

在阅读了这里的答案后,我决定使用它,是的,它在空间/时间上以某种方式更好,过了一会儿我改变了主意,我再也不会使用它了。当使用准备好的语句、库等 (php) 时,它使我的开发变得复杂了很多。bit(1)

从那以后,我总是用,似乎已经足够好了。tinyint(1)

评论

3赞 Chazy Chaz 12/21/2018
想解释一下它以什么方式使你的发展复杂化?
0赞 maembe 5/31/2019
@ChazyChaz它需要 true/false 而不是 1/0,这与 SQL Server 等其他一些数据库不同。这有时会导致奇怪的情况,你认为你把它设置为真的,但实际上并没有发生。
9赞 Paul Spiegel 5/27/2019 #12

由于 MySQL (8.0.16) 和 MariaDB (10.2.1) 都实现了 CHECK 约束,我现在将使用

bool_val TINYINT CHECK(bool_val IN(0,1))

您只能存储 、 或 ,以及可以转换为或不转换为错误(如 、 或 /)的值。01NULL01'1'0x00b'1'TRUEFALSE

如果不想允许 NULL,请添加以下选项NOT NULL

bool_val TINYINT NOT NULL CHECK(bool_val IN(0,1))

请注意,如果使用 ,则几乎没有区别。TINYINTTINYINT(1)TINYINT(123)

如果希望架构向上兼容,还可以使用 或BOOLBOOLEAN

bool_val BOOL CHECK(bool_val IN(TRUE,FALSE))

db<>fiddle 演示

评论

0赞 santiago arizti 8/9/2019
枚举(0, 1)呢
3赞 Paul Spiegel 8/9/2019
@santiagoarizti(必须是 - 注意:这些是字符串)不是一个好主意。由于内部存储方式以及如何处理非字符串值,存在太多问题。例如。 并且不能存储。 并成为 .并成为.ENUMenum('0', '1')0FALSE1TRUE'0'2'1'
0赞 dolmen 11/6/2019
最佳答案...对于使用 MySQL 8+ 的用户
2赞 Premkumar chalmeti 4/26/2020 #13

您可以使用 BOOL(BOOLEAN 数据类型)来存储布尔值。

这些类型是 TINYINT(1) 的同义词

然而, BIT(1) 数据类型更适合存储布尔值(true[1] 或 false[0]),但 TINYINT(1) 在输出数据、查询等操作时更容易使用,并实现 MySQL 和其他数据库之间的互操作性。您也可以查看此答案或主题

MySQL 还将 BOOL、BOOLEAN 数据类型转换为 TINYINT(1)。

此外,请阅读文档