Oracle中的布尔字段

150

昨天我想给一个Oracle表添加一个布尔字段。但实际上,Oracle没有布尔数据类型。这里有没有人知道模拟布尔的最佳方法?通过谷歌搜索这个问题,发现了几种方法:

  1. 使用整数,并且只需要分配0或1。

  2. 使用具有“Y”或“N”作为唯二值的字符字段。

  3. 使用带有CHECK约束的枚举。

有经验的Oracle开发人员知道哪种方法是首选/规范吗?


205
我希望Oracle有一个“墙”数据类型,这样当我使用布尔值时就可以把头撞在上面了。 - Greg
8个回答

86

我发现这个链接很有用。

以下是一个段落,其中列举了每种方法的一些优缺点。

最常见的设计是模仿 Oracle 数据字典视图使用的许多布尔式标识,选择 'Y' 表示 true,选择 'N' 表示 false。然而,为了与主机环境(例如 JDBC、OCCI 和其他编程环境)正确交互,选择 0 表示 false,选择 1 表示 true 更好,因为这样可以正确地与 getBoolean 和 setBoolean 函数配合使用。

基本上,他们提倡第二种方法,出于效率考虑,使用:

  • 为 0/1(由于与 JDBC 的 getBoolean() 等的互操作性)和检查约束条件
  • 类型为 CHAR(因为它比 NUMBER 占用更少的空间)。

他们的示例:

create table tbool (bool char check (bool in (0,1));
insert into tbool values(0);
insert into tbool values(1);`

36
我建议不要使用“N”和“Y”,因为它与语言有关。 英语为母语的人有时会忘记,大部分世界并不用字母Y代表真理概念。相比之下,0和1的含义跨越语言障碍是一致的。 - Andrew Spencer
7
在计算机科学中,“0”和“1”作为布尔值并不一致 - shell脚本类型的语言通常将“0”表示为成功,非零表示失败,而C类型的语言通常将“0”表示为失败,非零表示成功。 - Phil
43
作为布尔值,它们是明确无歧的。过程返回码不是布尔值。 - Andrew Spencer
15
为何在答案中忽略了提供链接中的这整段话?“最常见的设计是模仿Oracle数据字典视图使用的许多类布尔标志,选择“Y”表示true,“N”表示false。然而,为了与主机环境(如JDBC、OCCI和其他编程环境)正确交互,更好的选择是选择0表示false,1表示true,以便可以正确地与getBoolean和setBoolean函数一起工作。”文章指出,虽然“Y/N”很常见,但使用“0/1”可以增加与主机环境的兼容性,因此更为推荐。 - justin.hughey

28

Oracle本身使用Y/N表示布尔值。为了完整起见,应该指出PL/SQL有一个布尔类型,只有表没有。

如果您正在使用该字段指示记录是否需要进行处理,则可以考虑使用Y和NULL作为值。这样可以创建一个非常小的(读取快速)索引,占用非常少的空间。


7
关于Oracle内部视图和表使用Y/N的好处,非常有见地。如果Oracle这样做,那一定是正确的! :) - Jeffrey Kemp
你能解释一下为什么 Y 和 NULL 相比 Y 和 N 会生成一个较小的索引吗? - styfle
7
在 Oracle 中,NULL 值不会被索引。因此,如果你的索引包含一些 Y 字符但大部分是 NULL 值,那么你的索引将非常小。 - Leigh Riffel

25

为了使用最少的空间,您应该使用一个被限制为 'Y' 或 'N' 的 CHAR 字段。 Oracle 不支持 BOOLEAN、BIT 或 TINYINT 数据类型,因此 CHAR 的一个字节是您能够获得的最小大小。


19
最佳选择是0和1(作为数字-另一个答案建议使用空间效率更高的CHAR,但这对我来说有点扭曲),使用NOT NULL和检查约束将内容限制为这些值。(如果您需要列可为空,则您处理的不是布尔值,而是具有三个值的枚举...)
0/1的优点:
  • 与语言无关。如果每个人都使用“Y”和“N”,那么“Y”和“N”就没问题了。但他们没有这样做。在法国,他们使用“O”和“N”(我亲眼见过)。我没有在芬兰编程,看看他们是否在那里使用“E”和“K”-毫无疑问,他们比这聪明,但您不能确定。
  • 符合广泛使用的编程语言(C、C ++、Perl、Javascript)的惯例
  • 与应用程序层更好地配合,例如Hibernate
  • 导致更简洁的SQL,例如,要查找有多少香蕉可以食用 select sum(is_ripe) from bananas 而不是 select count(*) from bananas where is_ripe = 'Y' 或甚至(yuk) select sum(case is_ripe when 'Y' then 1 else 0) from bananas
“Y” / “N”的优点:
  • 占用的空间比0/1少
  • 这是Oracle建议的,因此可能是某些人更习惯的东西
另一个帖子建议使用'Y'/null以获得性能提升。如果您已经 证明 您需要性能,则可以使用,但否则请避免,因为它使查询不太自然(some_column is null 而不是 some_column = 0)而且在左连接中,您会将错误与不存在的记录混淆。

3
您发现最近很多布尔值是三态的,即真、假和未知。这与数据库中的空值概念非常相符,因为很多时候知道没有给出答案是至关重要的。 - MikeT
1
是的,可以需要真-假-未知,但如果我很挑剔(我确实是),我会说它不应该被描述为布尔值,因为它不是。 - Andrew Spencer
2
如果你要这么挑剔的话,那么你可以对每种数据类型都提出同样的论点。在严格的定义下,整数、双精度浮点数(我想我应该说双长度二进制补码浮点数)、二进制、字符串等都假定提供了一个值,但数据库实现总是添加了一个空值选项,布尔型也不例外。 - MikeT
1
如果您正确配置数字,则其可以与char字段存储在同一字节中,这对于使用0/1无大小论据也是有益的。我目前找不到链接,但数字的存储范围为1-22个字节,具体取决于配置。 - MikeT
4
我怀疑这些反对票是由于一种传统思维方式选择了最节约内存的实现方式。如今,内存效率远不如可用性和兼容性重要,并且应在考虑这些因素后再加以考虑。如果有人回复此评论,我建议您了解“过早优化”。仅基于内存效率而选择“是/否”正是正在发生的情况。由于这个决定,您正在失去与一组常用框架的本机兼容性。 - justin.hughey
显示剩余4条评论

5

可以使用1/0或Y/N的检查约束。两种方式都可以。个人更喜欢使用1/0,因为我在perl中做了很多工作,这使得在数据库字段上进行perl布尔运算变得非常容易。

如果您想要与Oracle高管之一就此问题进行深入讨论,请查看Tom Kyte在此处的发言。


据说1/0“内存效率较低”,但是...我也更喜欢它(而且似乎Hibernate需要1/0来表示布尔值)。 - rogerdpack
1/0 是 Hibernate 中布尔类型的默认值,但你可以定义任何自定义映射。 - Andrew Spencer
@rogerdpack那是因为char字段是1个字节,nchar字段是2个字节,而数字字段根据定义的方式可以占用1到22个字节。 - MikeT

4
我大部分工作涉及的数据库使用“Y” / “N”作为布尔值。使用这种实现方法,您可以执行一些技巧,例如:
  1. 计算真实行数:
    SELECT SUM(CASE WHEN BOOLEAN_FLAG = 'Y' THEN 1 ELSE 0) FROM X

  2. 在对行进行分组时,强制执行“如果一行为真,则所有行都为真”的逻辑:
    SELECT MAX(BOOLEAN_FLAG) FROM Y
    相反,如果有一行为假,则使用MIN来强制分组为假。


4
实际上,所展示的例子对于0/1方法也很有用,并且在我看来更快。 - igorsantos07

3

以下是一个可行的示例,用于将“布尔”列添加到 Oracle 数据库中现有表格(使用number类型)并实现已接受的答案:

ALTER TABLE my_table_name ADD (
my_new_boolean_column number(1) DEFAULT 0 NOT NULL
CONSTRAINT my_new_boolean_column CHECK (my_new_boolean_column in (1,0))
);

这将在my_table_name中创建一个名为my_new_boolean_column的新列,默认值为0。该列不接受NULL值,并限制可接受的值为01

1
在我们的数据库中,我们使用枚举确保我们传递TRUE或FALSE。如果您使用前两种方法之一,很容易开始向整数添加新含义而不经过适当的设计,或者最终使该字符字段具有Y、y、N、n、T、t、F、f值,并且必须记住哪个代码部分使用哪个表以及使用哪个版本的true。

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