【问题标题】:Boolean Field in OracleOracle 中的布尔字段
【发布时间】:2010-09-07 00:02:04
【问题描述】:

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

  1. 使用整数,不要为它分配除 0 或 1 以外的任何值。

  2. 使用 char 字段,将“Y”或“N”作为仅有的两个值。

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

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

【问题讨论】:

  • 我希望 Oracle 有一个 wall 数据类型,这样我就可以在使用布尔值时撞到它。

标签: oracle boolean sqldatatypes


【解决方案1】:

我发现this 链接很有用。

以下段落强调了每种方法的一些优点/缺点。

最常见的设计是模仿许多类似布尔的 Oracle 的数据字典视图使用的标志,选择“Y”表示真 'N' 代表错误。但是,要与主机正确交互 环境,例如 JDBC、OCCI 和其他编程环境, 最好选择 0 表示 false 和 1 表示 true 以便它可以工作 正确使用 getBoolean 和 setBoolean 函数。

基本上他们提倡方法2,为了效率,使用

  • 为 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);`

【讨论】:

  • 我建议不要使用“N”和“Y”,因为它取决于语言。讲英语的人有时会忘记,世界上大多数地方并不用字母 Y 来代表真理的概念。相比之下,0 和 1 的含义跨越语言障碍是不变的。
  • 0 和 1 作为布尔值在计算机科学中不一致 - shell 脚本类型语言倾向于将 0 作为成功,而非零作为失败,而 C 类型语言倾向于将 0 作为失败, 非零表示成功。
  • 作为 boolean 值,它们是明确的。进程返回码不是布尔值。
  • 为什么此答案中忽略了提供的链接中的整个段落? “最常见的设计是模仿 Oracle 的数据字典视图使用的许多类似布尔值的标志,选择“Y”代表真,“N”代表假。但是,要与主机环境正确交互,例如 JDBC、OCCI、和其他编程环境,最好选择 0 代表 false 和 1 代表 true 以便它可以正确使用 getBoolean 和 setBoolean 函数。”他们指出,虽然“Y/N”很常见,但建议使用“0/1”来增加与主机环境的兼容性。
【解决方案2】:

Oracle 本身使用 Y/N 作为布尔值。为了完整起见,应该注意 pl/sql 具有布尔类型,只有表没有。

如果您使用该字段来指示是否需要处理记录,您可以考虑使用 Y 和 NULL 作为值。这使得索引非常小(读取速度快),占用的空间非常少。

【讨论】:

  • +1 关于使用 Y/N 的 Oracle 内部视图和表的要点。如果 Oracle 这样做,那一定是对的! :)
  • 你能解释一下 Y 和 NULL 与 Y 和 N 相比如何形成一个小索引吗?
  • NULL 不会在 Oracle 中建立索引,因此如果您的索引包含几个 Y 字符,但大多数是 NULL,那么您的索引将非常小。
【解决方案3】:

要使用最少的空间,您应该使用限制为“Y”或“N”的 CHAR 字段。 Oracle 不支持 BOOLEAN、BIT 或 TINYINT 数据类型,因此 CHAR 的 1 字节尽可能小。

【讨论】:

    【解决方案4】:

    最好的选择是 0 和 1(作为数字 - 另一个答案建议 0 和 1 作为 CHAR 以提高空间效率,但这对我来说有点太扭曲了),使用 NOT NULL 和检查约束将内容限制为这些值。 (如果您需要该列可以为空,那么它不是您要处理的布尔值,而是具有三个值的枚举......)

    0/1的优点:

    • 语言无关。如果每个人都使用它,“Y”和“N”就可以了。但他们没有。在法国,他们使用“O”和“N”(我亲眼目睹了这一点)。我还没有在芬兰编程看看他们是否在那里使用“E”和“K”——毫无疑问他们比那更聪明,但你不能确定。
    • 符合广泛使用的编程语言(C、C++、Perl、Javascript)的实践
    • 与应用层配合使用效果更好,例如休眠
    • 导致更简洁的 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)并且在左连接中你会混为一谈不存在的记录是虚假的。

    【讨论】:

    • 你发现现在很多布尔值都是三态的,即真、假和未知。这完全符合数据库空的想法。仅仅因为很多时候知道没有答案是至关重要的
    • 是的,可能需要 true-false-unknown,但如果我很挑剔(我就是这样),我会说它不应该被描述为布尔值,因为它不是.
    • 如果您要那么挑剔,那么您可以为每种数据类型使用相同的参数。正如在严格定义下的整数、双精度(我想我应该说双倍长度二进制补码浮点)、二进制、字符串等都假设提供了一个值,但数据库实现总是添加一个空值选项布尔没有任何不同跨度>
    • true,如果你正确配置了你的数字,它也可以存储在与 char 字段相同的单个字节中,这会使 size 参数无效,而不是使用 0 / 1,i目前找不到链接,但根据配置存储的数字范围为 1 - 22 个字节
    • 我怀疑投反对票是由于传统观点认为选择内存效率最高的实现。当今时代的内存效率远没有那么重要,应该在可用性和兼容性之后考虑。对于任何可能对此评论做出回应的人,我建议阅读有关过早优化的内容。这正是纯粹基于内存效率选择“Y/N”所发生的情况。由于该决定,您将失去与一组常用框架的本机兼容性。
    【解决方案5】:

    1/0 或 Y/N 都带有检查约束。以太方式很好。我个人更喜欢 1/0,因为我在 perl 中做了很多工作,它使得对数据库字段进行 perl 布尔运算变得非常容易。

    如果您想与 Oracle 的一位负责人就这个问题进行深入讨论,请查看 Tom Kyte 对此 Here 的看法

    【讨论】:

    • 1/0 被认为是“内存效率较低”,但是...我也更喜欢它(而且 hibernate 显然需要 1/0 作为布尔值)
    • 1/0 是 Hibernate 的默认布尔值,但您可以定义任何您喜欢的自定义映射。
    • @rogerdpack 那是因为 char 字段是 1 个字节,或者 nchar 是 2 个字节,其中取决于它的定义方式,数字可以是 1 到 22 个字节
    【解决方案6】:

    我完成大部分工作的数据库使用“Y”/“N”作为布尔值。通过该实现,您可以完成一些技巧,例如:

    1. 计算正确的行数:
      SELECT SUM(CASE WHEN BOOLEAN_FLAG = 'Y' THEN 1 ELSE 0) FROM X

    2. 对行进行分组时,强制执行“如果一行为真,则所有为真”的逻辑:
      从 Y
      中选择 MAX(BOOLEAN_FLAG) 反之,如果一行为假,则使用 MIN 强制分组为假。

    【讨论】:

    • 事实上,显示的示例对于 0/1 方法也很有用 - 而且,恕我直言,更快。
    【解决方案7】:

    通过将“布尔”列添加到 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

    【讨论】:

      【解决方案8】:

      在我们的数据库中,我们使用一个枚举来确保我们将其传递为 TRUE 或 FALSE。如果您使用前两种方法中的任何一种,则很容易在没有经过适当设计的情况下开始为整数添加新含义,或者以具有 Y、y、N、n、T、t 的 char 字段结束, F,f 值,并且必须记住哪段代码使用哪个表以及它使用的是哪个版本的 true。

      【讨论】:

        猜你喜欢
        • 2015-01-24
        • 2013-10-26
        • 2010-09-19
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2018-09-18
        • 2018-11-20
        • 2010-12-23
        相关资源
        最近更新 更多