代码之家  ›  专栏  ›  技术社区  ›  Robert

为什么mysql-if函数不转换null?

  •  -1
  • Robert  · 技术社区  · 1 年前

    我有一个mysql数据库,其中一些表使用了实体属性值anti-pattern。我需要查询该表并引入属性。我想把它们作为布尔值,即左连接给我的地方 null (对于不存在的)属性,我想获取 false ,如果属性存在,我想得到 true (或0和1)。

    select 
        -- cap.type as over_21  -- ok: some null, some "over_21"
        -- coalesce(cap.type, false) as over_21    -- ok: some 0, some "over_21"
        -- (case when type is not null then 1 else 0 end) as over_21   -- ok: some 0, some 1
        if (cap.type, true, false) as over_21   -- wrong: all 0
        -- if (cap.type is null, false, true) as over_21  -- ok again
    from customer c
    left join capabilities cap
    on c.id = cap.user_id
    and cap.type = 'over_21'
    

    到目前为止,第一条评论的路线是可行的,它给了我 无效的 或者属性类型,这里是“over21”。(该表没有我可以使用的值字段;如果记录存在,则意味着属性已设置。)

    coalesce case 以上工作如预期,但当我使用 if ,the over_21 列仅显示0。

    这个 IF() function documentation 说:

    如果expr1为TRUE(expr1<>0且expr1不为NULL),则If()返回expr2。否则,它将返回expr3。

    鉴于我的 expr1 有时 无效的 ,我以为这会把它们很好地变成0和非0- 无效的 s为1(或假和真)。它确实适用于显式 is null 检查。

    为什么不 如果 转换我的 无效的 值转换为布尔值?

    1 回复  |  直到 1 年前
        1
  •  2
  •   Bill Karwin    1 年前

    NULL既不是布尔值false,也不是整数0。

    如果它是假的,那么 NOT (NULL) 这是真的,对吧?但事实并非如此:

    mysql> select not null;
    +----------+
    | not null |
    +----------+
    |     NULL |
    +----------+
    

    将NULL视为“未知”

    如果我不告诉你我的中间名,有人问你比尔的中间名是戴夫?你会说“我不知道”

    如果他们问你是比尔的中间名 戴夫?你只能再说一次“我不知道”。


    测试您的查询:

    CREATE TABLE customer (
      id INT AUTO_INCREMENT primary key
    );
    
    INSERT INTO customer VALUES (1), (2), (3);
    
    CREATE TABLE capabilities (
      user_id INT NOT NULL,
      type VARCHAR(10)
    );
    
    INSERT INTO capabilities VALUES
    (1, 'over_21'),
    (2, 0),
    (3, NULL);
    
    select
        c.id, cap.type, cast(cap.type as unsigned),
        if (cap.type, true, false) as over_21   
    from customer c
    left join capabilities cap
    on c.id = cap.user_id
    and cap.type = 'over_21';
    

    结果:

    +----+---------+----------------------------+---------+
    | id | type    | cast(cap.type as unsigned) | over_21 |
    +----+---------+----------------------------+---------+
    |  1 | over_21 |                          0 |       0 |
    |  2 | NULL    |                       NULL |       0 |
    |  3 | NULL    |                       NULL |       0 |
    +----+---------+----------------------------+---------+
    

    那么为什么user_id 1的结果是0呢?

    因为在布尔上下文中,字符串不是隐式为真的。在MySQL中,布尔值和整数是相同的,所以这实际上是一个整数上下文。

    在整数上下文中求值的字符串通过读取任何初始数字字符并忽略其余字符隐式转换为数字。如果没有初始数字字符,则字符串的数值为0。0对MySQL来说是假的。

    mysql> warnings;
    Show warnings enabled.
    
    mysql> select 'over_21' + 0;
    +---------------+
    | 'over_21' + 0 |
    +---------------+
    |             0 |
    +---------------+
    1 row in set, 1 warning (0.00 sec)
    
    Warning (Code 1292): Truncated incorrect DOUBLE value: 'over_21'