Oracle - 如何模拟位列和布尔AND/OR?

30 浏览
0 Comments

Oracle - 如何模拟位列和布尔AND/OR?

我来自MS SQL和MySQL。这些数据库管理系统提供了一种位数据类型,其中两个布尔值由0和1表示。

我现在参与了一个对我来说是新的Oracle项目。它(某个地方)建议将NUMBER(1)用作位 - 因此值0和1将会存在,但它还支持值-9到-1和2到9。

我们必须在两个这样的列之间进行OR操作。

我还阅读了这篇文章。但是,对于OR(和AND)功能来说,什么是最好的选择,既少写样板代码,又易读(对程序员来说)和高效?

这是一些用于检查的测试代码:

--删除test_bool_number表;
创建表test_bool_number(
    test_id NUMBER GENERATED BY DEFAULT AS IDENTITY,
    abool NUMBER(1),
    bbool NUMBER(1),
    cbool NUMBER(1)
    PRIMARY KEY(test_id)
);
INSERT INTO test_bool_number(abool,bbool,cbool)
            select 0, 0, null from dual
  union all select 0, 1, null from dual
  union all select 1, 0, null from dual
  union all select 1, 1, null from dual;
SELECT * FROM test_bool_number ORDER BY test_id; -- 查询结果

团队成员建议使用:

-- 选项A + 表示OR,* 表示AND
UPDATE test_bool_number
  SET
    cbool = abool + bbool;

我发现这个版本可能有效,如果cbool在Java类布尔属性中进行反序列化,但它并不总是有效:

  • abool和bbool只能是0或1
  • 结果cbool不满足上述条件,如果cbool > 0,则为true
  • 如果像这样总结10个以上的布尔列,结果为10,在number(1)中会导致ORA-01438错误

然后我发现了这个:

-- 选项B greatest表示OR,least表示AND
UPDATE test_bool_number
  SET
    cbool = greatest(abool, bbool);

上述方法很好用,因为结果始终为0或1,但仅限于:

  • abool和bbool只能是0或1
  • 对于10个或更多列进行OR操作也适用。对于AND操作,可以使用least方法。

但是,如果有人以第一种方式或其他方式计算中间布尔结果 - abool和bbool的值也可以是-9至-1或2至9!

假设所有非0值都代表true(例如C编程语言中的表示方式)

获取布尔值OR的最简单代码是什么?

-- 在true的情况下,bool输入值并不总是只有1!
UPDATE test_bool_number
  SET abool = abool * -5, bbool = bbool * +5;
-- 选项C 标准SQL始终正确   
UPDATE test_bool_number
  SET cbool = case when ((abool <> 0) or (bbool <> 0)) then 1 else 0 end;

上述语句完全正确,但有很多样板代码。

所以我找到了另一个选择:

-- 选项D ABS和SIGN
UPDATE test_bool_number
  SET
    cbool = SIGN(ABS(abool) + ABS(bbool));

它更短,始终正确。即使abool = 9和bbool = 7,并且中间结果为SIGN(16),其中16超出了NUMBER(1)的范围,但它是否高效?

是否有更简单的方法,甚至是高效的方法来处理布尔值?

还是更好地在Oracle表列中表示布尔值的方式是NUMBER(1)以0 = false和1(或其他)= true?

-- 选项E ABS + > 0
UPDATE test_bool_number
  SET
    cbool = case when ((ABS(abool) + ABS(bbool)) > 0) then 1 else 0 end;

那么使用二进制或位OR如何?

-- 选项F 用于OR的BITOR
UPDATE test_bool_number
  SET
    cbool = BITOR(abool, bbool) <> 0 then 1 else 0 end;

上述方法仅适用于OR,无法使用BITAND实现AND功能。

只是一些神奇的想法,对于下一个代码阅读者来说并不容易理解:

-- 选项G 通过文本
UPDATE test_bool_number
  SET
    cbool = ABS(SIGN(TO_NUMBER(abool || bbool)));

最内部的部分可以理解为布尔或,就像在许多编程语言(C#,Java等)中一样,但在Oracle中它是一个字符串连接运算符!

所以我们得到了'00','10'等。

最后它只返回0或1,但仅当(abool和)bbool是正值或0时!

而且我怀疑性能(数字转换为文本,文本再转换为数字)。

那么你在Oracle中如何处理布尔值,什么方法最适合能够构建一个可理解的OR(和AND)代码来处理2个或更多其他布尔列,并且性能相当好?

你是否使用其他列类型来表示布尔值?字符?'0'和'1'或'y'和'n'?对于2...n列,你如何进行OR(和AND)操作?

0
0 Comments

Oracle数据库中没有直接实现位列(bit column)或布尔AND/OR操作的内置功能。然而,可以使用BITAND和BITOR函数来模拟位列和布尔AND/OR操作,并在相关的列上添加CHECK约束来实现。

以下是一个示例代码,展示了如何使用BITAND和BITOR函数以及CHECK约束来模拟位列和布尔AND/OR操作:

SELECT abool,
       bbool,
       BITAND(abool, bbool),
       BITOR(abool, bbool)
FROM   test_bool_number
ORDER BY test_id;

上述代码中的test_bool_number表包含了两个列(abool和bbool),它们都被限制为只能取0或1的值。通过在这两列上添加CHECK约束,可以确保它们只能取合法的值。

在Oracle 11及以上版本中,可以使用BITAND函数来模拟位与操作,而在Oracle 21中,可以使用BITOR函数来模拟位或操作。需要注意的是,BITOR函数在文档中并未明确提及,但实际上是可用的。如果在Oracle 21之前的版本中需要使用BITOR函数,可以创建一个用户自定义函数来实现。

在执行上述代码后,将得到以下输出:

| ABOOL | BBOOL | BITAND(ABOOL,BBOOL) | BITOR(ABOOL,BBOOL) |

|-------|-------|--------------------|-------------------|

| 0 | 0 | 0 | 0 |

| 0 | 1 | 0 | 1 |

| 1 | 0 | 0 | 1 |

| 1 | 1 | 1 | 1 |

通过BITAND和BITOR函数,我们可以模拟位列和布尔AND/OR操作,得到期望的结果。

需要注意的是,虽然BITAND函数在文档中有明确的说明,但BITOR函数并未在文档中找到。此外,BITXOR函数也未在文档中找到,但它也是可用的。在Oracle 21中,还引入了许多新的二进制函数,包括BIT_AND_AGG、BIT_OR_AGG和BIT_XOR_AGG,它们都在文档中有明确的说明。此外,BITOR和BITXOR函数也被引入了,但似乎未在文档中记录。

总结起来,使用BITAND和BITOR函数以及CHECK约束可以在Oracle数据库中模拟位列和布尔AND/OR操作。但与SQL Server或MySQL不同,PostgreSQL实际上在数据库中实现了真正的布尔类型,这更加清晰和直观。

0