首页 > 解决方案 > 为什么在 where 子句中的 char 字段上使用合并时查询结果会发生变化?

问题描述

在 Oracle 数据库中使用 where 子句查询合并的 char 字段时,我看到了一些意外行为。

结果好像

CASE WHEN COALESCE(char_field, 'some_val') = 'someOtherVal'

与结果不同

CASE WHEN char_field = 'someOtherVal'

我注意到这个奇怪输出的具体比较是“介于”、“在”和“等于”。这些是我看到的奇怪输出:

  1. 上端之间似乎不包含在内
  2. In 和 equals 每次比较都返回 false

这是一些复制怪异的sql:

CREATE TABLE delete_me( some_char CHAR(8) );

INSERT ALL   
  INTO delete_me (some_char) VALUES ('1')
  INTO delete_me (some_char) VALUES ('2')
  INTO delete_me (some_char) VALUES ('4')
  INTO delete_me (some_char) VALUES ('5')
  INTO delete_me (some_char) VALUES ('abc1')
  INTO delete_me (some_char) VALUES (null)
SELECT 1 FROM DUAL;

SELECT some_char,
  COALESCE(some_char, 'wasNull') AS coalesce_some_char,
  CASE
    WHEN (some_char BETWEEN '1' AND '5')
    THEN 'true'
    ELSE 'false'
  END AS between_1_5,
  CASE
    WHEN (COALESCE(some_char, 'wasNull') BETWEEN '1' AND '5')
    THEN 'true'
    ELSE 'false'
  END AS coalesce_between_1_5,
  CASE
    WHEN (some_char IN ('1', '5'))
    THEN 'true'
    ELSE 'false'
  END AS in_1_5,
  CASE
    WHEN (COALESCE(some_char, 'wasNull') IN ('1', '5'))
    THEN 'true'
    ELSE 'false'
  END AS coalesce_in_1_5,
  CASE
    WHEN (some_char = 'abc1')
    THEN 'true'
    ELSE 'false'
  END AS equals_abc1,
  CASE
    WHEN (COALESCE(some_char, 'wasNull') = 'abc1')
    THEN 'true'
    ELSE 'false'
  END AS coalesce_equals_abc1
FROM delete_me;

对于除 IS NULL 之外的所有运算符,我本来希望合并字段上的比较输出与非合并字段上的输出相匹配。

有谁知道为什么这些结果不匹配?

标签: sqloraclecharbetweencoalesce

解决方案


您的问题出在some_char. 当一个类型的列CHAR与一个字符串进行比较时,Oracle 将字符串填充到该列的长度(请参阅文档)。在您正在进行的测试中,值的长度匹配('1'vs '1')或完全不同('1'vs 'abc1'),所以一切正常。但是,当您COALESCECHAR字段上使用时,输出是作为 a 返回COALESCE的完全空白的填充列值(请参阅NVL 的文档),因此比较字符串不是空白填充,然后您正在比较vs ,但失败了。有几种方法可以解决这个问题。你可以输出VARCHAR'1 ''1'TRIMCOALESCEIE

TRIM(COALESCE(some_char, 'wasNull'))

或将数据类型更改some_charVARCHAR(8)改为。

我在dbfiddle上做了一个演示


推荐阅读