为什么在 where 子句中对 char 字段使用 coalesce 时查询结果会发生变化?
Why do query results change when using coalesce on a char field in a where clause?
我在 Oracle 数据库的合并字符字段上使用 where 子句查询时发现一些意外行为。
好像
的结果
CASE WHEN COALESCE(char_field, 'some_val') = 'someOtherVal'
与
的结果不同
CASE WHEN char_field = 'someOtherVal'
我注意到这个奇怪输出的具体比较是 'between'、'in' 和 'equals'。这些是我看到的奇怪输出:
- Between在上端似乎是非包容性的
- 每次比较都等于return 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 之外的所有运算符,合并字段的比较输出与非合并字段的比较输出相匹配。
有谁知道为什么这些结果不匹配?
您的问题出在 some_char
的数据类型上。当 CHAR
类型的列与字符串进行比较时,Oracle 将字符串空白填充到列的长度(参见 docs). In the tests you are doing, the values match in length ('1'
vs '1'
) or are completely different ('1'
vs 'abc1'
) so everything works fine. However when you use COALESCE
on a CHAR
field, the output of COALESCE
is the fully blank padded column value returned as a VARCHAR
(see the docs for NVL),因此比较字符串是 not 空白填充,然后您比较 '1 '
与 '1'
,但失败了。有几种方法可以解决这个问题。您可以 TRIM
COALESCE
的输出,即
TRIM(COALESCE(some_char, 'wasNull'))
或将 some_char
的数据类型更改为 VARCHAR(8)
。
我已经在 dbfiddle
上制作了所有这些的演示
我在 Oracle 数据库的合并字符字段上使用 where 子句查询时发现一些意外行为。
好像
的结果CASE WHEN COALESCE(char_field, 'some_val') = 'someOtherVal'
与
的结果不同CASE WHEN char_field = 'someOtherVal'
我注意到这个奇怪输出的具体比较是 'between'、'in' 和 'equals'。这些是我看到的奇怪输出:
- Between在上端似乎是非包容性的
- 每次比较都等于return 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 之外的所有运算符,合并字段的比较输出与非合并字段的比较输出相匹配。
有谁知道为什么这些结果不匹配?
您的问题出在 some_char
的数据类型上。当 CHAR
类型的列与字符串进行比较时,Oracle 将字符串空白填充到列的长度(参见 docs). In the tests you are doing, the values match in length ('1'
vs '1'
) or are completely different ('1'
vs 'abc1'
) so everything works fine. However when you use COALESCE
on a CHAR
field, the output of COALESCE
is the fully blank padded column value returned as a VARCHAR
(see the docs for NVL),因此比较字符串是 not 空白填充,然后您比较 '1 '
与 '1'
,但失败了。有几种方法可以解决这个问题。您可以 TRIM
COALESCE
的输出,即
TRIM(COALESCE(some_char, 'wasNull'))
或将 some_char
的数据类型更改为 VARCHAR(8)
。
我已经在 dbfiddle
上制作了所有这些的演示