Oracle 缺少表列的 Bit 数据类型

Posted

技术标签:

【中文标题】Oracle 缺少表列的 Bit 数据类型【英文标题】:Oracle's lack of a Bit datatype for table columns 【发布时间】:2011-01-26 10:29:07 【问题描述】:

Oracle 不支持 bit 数据类型或任何其他类型的真/假方案。是否有人使用char(1) 字段而不是使用特定字母来表示是/真,而不管文化特定问题如何?

应该用Number(1,0) 代替char - 0 被认为是假/否,其他任何东西都被解释为真/是?

这可行吗?


为什么 Oracle 不支持简单的布尔类型?

【问题讨论】:

在所有保留下,Oracle 不提供 BOOL 或 BOOLEAN(也许只有最新版本......)数据类型?我真的记不太清楚了。我已经两年多没有做Oracle了。反正 NUMBER(1) 就可以了,它说它需要什么,就像一个 BIT - 0 或 1,一个 NUMBER(1) - 0 或 1,有什么区别? @Will: Number(1, 0) 可以是任何一位数 (0-9),而不仅仅是 0 或 1。 是的,当然!但是您无法控制数据表列的值吗? @Will:不幸的是,Oracle 没有为表中的数据提供 Bit 或 Boolean 作为可接受的数据类型......至于你限制为 0 或 1,我同意你的看法 - 这是如果我是我们项目的技术负责人,我们会采取什么样的方式 - 但可惜我不是...... 另见关于布尔数据类型的类似问题:***.com/questions/3726758/… 【参考方案1】:

使用CHAR(1) 和一个仅允许10 的约束。

...

col CHAR(1),
CONSTRAINT cons_atable_col1 CHECK (col1 IN ('1','0'))

【讨论】:

这就是我在对这个案子做了进一步研究之后要写的。无论如何,这是一个应该有帮助的链接。 thinkoracle.blogspot.com/2005/07/oracle-boolean.html 此外,您可以为自己定义一个用户类型,例如 BIT,然后只接受那些受限制的值。另一个有用的链接:download-uk.oracle.com/docs/cd/B19306_01/server.102/b14200/… 如有必要,不要忘记“默认 0 非空”。我测试了必要性 - 避免空插入【参考方案2】:

我不是英语母语,所以我倾向于使用 1 和 0 或“1”和“0”。如果您不是用英语编码(是的,确实存在母语编码),则使用“Y”和“N”毫无意义。使用“SI”和“NO”或“S”和“N”看起来并不专业(就像用重音字母命名变量一样)。相反,如果您使用 C、phpjavascript 编码,则 1 和 0 是相当标准的。无论如何,我总是添加适当的约束来禁止任何其他字符。除了主观问题之外,我认为选择 CHAR 或 NUMBER 不会有明显的性能提升。我更喜欢数字,因为我不需要引用它们:)

我同意这是一个明显的遗漏,但我已经阅读了一些 Oracle 论坛上关于该主题的激烈讨论;这是一种宗教问题。一些人声称布尔值属于应用程序数据类型,在数据库核心中没有位置。老实说,我相信这是我们很久没有使用它的原因之一,我们最好说这是故意的。

顺便说一句,mysql 有一个 BOOLEAN 类型,但它是 TINYINT(1) 的同义词,所以它最终等于 1 和 0;这很好,因为它还有常量 TRUE 和 FALSE,它们的值分别为 1 和 0。

【讨论】:

我很想同意你的看法——是的,我过去做过一些 C/PHP。我绝对更喜欢数字,但我惊讶地发现它们占用了更多空间(见上文) +1 for "We-Have-Been-So-Long-Without-It-That-We-Had-Better-Say-It-Was-On-Purpose" 我们应该创造这个短语: WHBSLWITWHBSIWOP.【参考方案3】:

我更喜欢 char(1) 而不是 number(1),因为通过一些合理的字符选择,哪个字符具有哪个布尔含义是显而易见的。

当然,您应该与所有不同的变体作斗争,选择一个并通过在列上设置检查约束来确保它的使用。

虽然在您的情况下可能为时已晚,但从另一个工具生成架构通常至少会考虑一致性问题。为此,我个人更喜欢使用休眠模式,但这取决于具体情况。

当然,这是一个明显的遗漏。更糟糕的是,PL/SQL 有一个布尔值,但你不能在 SQL 语句中使用它。

【讨论】:

这和 Thilo 的答案都很好 - 但我接受了这个答案,因为建议通过检查约束强制合规......似乎真正的答案是“每个人都做自己的事,那里没有标准……” 您也可以相应地命名列,例如 UPDATE_ALLOWED_YN【参考方案4】:

这是关于该主题的Ask Tom 讨论。就该问题提供以 Oracle 为中心的观点。

至于存储,char(1) 实际上效率更高一点(不是双关语):

SQL> CREATE TABLE xx (c CHAR(1), n NUMBER);

Table created

SQL> insert into xx values('T', 1);

1 row inserted

SQL> select dump(c), dump(n) from xx;

DUMP(C)             DUMP(N)
------------------- -------------
Typ=96 Len=1: 84    Typ=2 Len=2: 193,2

【讨论】:

这很有趣 - 而不是我所期望的。我个人仍然觉得数字更清晰......我在看到你的帖子(谷歌搜索)之前阅读了 Ask Tom 的讨论,但我不同意他没有布尔 / 位的理由...... @Martin:请参阅此 SO 讨论以获得进一步的启发,特别注意 Quassnoi 的回答:***.com/questions/1087210/oracle-number-comparisons/… @Martin:我同意,在数据库中排除 BOOLEAN 类型没有合乎逻辑的理由,只有实用的类型。 Oracle 在这个问题上有点精神分裂,因为他们的 PL/SQL 语言中确实有 BOOLEAN 类型。仅此一项就让 Oracle 程序员在第一次遇到它时感到非常困惑。 谢谢你 - 不知道它们被存储为百分号......我在这份工作之前的背景主要关注 MS-SQL,我不得不说在很多方面我开始怀念它!【参考方案5】:

根据此 Oracle 指南 - 您应该使用 NUMBER(3)。疯狂,但真实。

http://docs.oracle.com/cd/B19306_01/gateways.102/b14270/apa.htm

【讨论】:

“根据这个Oracle指南”,实际上它是一个从MsSQL到Oracle的转换表。所以我不知道你是否真的应该使用这个指南来使用NUMBER(3)【参考方案6】:

Number(1) 并不比 char(1) 好。特别是如果它是现有 char(1) 的补充。这只会增加混乱。

FWIW,Oracle 在内部视图(例如 USER_TAB_COLUMNS)中使用 varchar2(3)(是和否)。不过,不确定它们在这里是否 100% 一致。

【讨论】:

我想到 Number(1,0) 的原因是,如果没有别的,值将具有明确定义的含义。我同意你的观点,无论我们做什么都必须与过去的代码共存,但这是不可避免的——而且不像简单地离开目前的情况那样不可取……我也希望数字性质是服务器更容易处理,因此可能(可以忽略不计)更快。您愿意提供候选数据类型吗? number(1) 在磁盘空间上可能会小一些,但除了几乎只包含“布尔”的巨大表之外,这应该可以忽略不计。此外,您始终可以选择压缩和位图索引,这可能会解决一些与空间相关的负面影响。 @Jens:实际上,number(1) 更大。看我的回答。 Oracle 使用不同的方式,'Y'/'N','YES'/'NO','ENABLED'/'DISABLED',甚至 'Y'/'N'(参见 all_tables.缓存列),+ 其他一些。连贯性都看不到。【参考方案7】:

这个问题很老,但在使用最新版本的 oracle 之前,它仍然是一个有效的问题。

我会这样解决问题: 创建一个表格,其中包含真/假的可能值以及本地化显示文本 f.e. T$关键字 ITEMNO ITEMTEXT ITEMTEXT_DE ITEMTEXT_FE ... 0 错误的 1 真正的瓦尔

除了 True/False,这也可以是 Selected、Not Selected 等。

然后在此表的列中添加一个外键。这样你就只有有效的值,它们不会随着本地化而改变。

恕我直言,另一个好的解决方案是对您的数据列使用检查约束。如果您的值在同一数据库/列中可能因客户端的本地化而不同,则此 ofc 不起作用。

alter table tblLocations add flag number CONSTRAINT <constraintname> CHECK (flag IN (1,0));

【讨论】:

【参考方案8】:

Oracle 在不同的数据字典视图中内部使用“位”(本身不是数据类型)。

例如,dba_users 视图有:

..
        , DECODE (BITAND (u.spare1, 128), 128, 'YES', 'NO')
..
        , DECODE (BITAND (u.spare1, 256), 256, 'Y', 'N')
..

这显示了以某种方式解决此问题的方法。如果您不必经常修改“布尔”位,则可以使用自 Oracle 6 以来 Oracle 所采用的相同方法(至少)。创建一个包含 NUMBER 列的表,并在其上添加一个隐藏 BITAND 操作复杂性的 VIEW。

ps。附带说明一下,Oracle JDBC 有一个“位”数据类型https://docs.oracle.com/cd/E16338_01/appdev.112/e13995/oracle/jdbc/OracleTypes.html#BIT,而且您已经知道 PL/SQL 有布尔值。虽然它可能对你没有多大帮助。如果它适合您的情况,请参阅上面的 BITAND 方法。

【讨论】:

【参考方案9】:

https://docs.oracle.com/cd/E17952_01/refman-5.5-en/char.html

正如 DCookie 所说,char(1) 更有效。 因为 VARCHAR2(VARCHAR) empty 包含 1 个字节,但是当我们存储 1 个字符时,空 1 字节大小 + 字符 1 字节大小 --> 2 字节需要在 varchar 中存储 1 个字符

【讨论】:

以上是关于Oracle 缺少表列的 Bit 数据类型的主要内容,如果未能解决你的问题,请参考以下文章

对于表列数据类型选择的一点思考

Oracle GoldenGate 生成表列时始终标识类型_IT 不允许在目标数据库表中插入

Oracle数据库中是否有任何布尔类型?

SqlBulkCopy 来自数据源的 String 类型的给定值不能转换为指定目标列的类型 bit

将数据框从 jupyter notebook 写入雪花而不定义表列类型

什么 Oracle 数据类型可以通过 SSIS 在 SQL 中轻松转换为 BIT?