sqlpostgresqlmybatisibatis

Migrate ibatis cases to native SQL


I have the following ibatis query:

update users
<set>
  <if test="reference != null ">
    reference = #{reference},
  </if>
  <if test="status != null">
    status_type = #{status},
  </if>
</set>
where id = #{id.id}

How I can migrate these checks (XML tags) into SQL checks for PostgreSQL database?


Solution

  • The basic idea is to use coalesce(new_value, old_value) to pick the new value over the old value if the new value is not null:

    create table users (id int, reference int, status_type int);
    insert into users values (1, 1, 1), (2, 2, 2), (3, 3, 3);
    
    update users
    set reference   = coalesce(t.reference, users.reference),
        status_type = coalesce(t.status_type, users.status_type)
    from (values (1, null, 11), (2, 12, null)) t(id,reference,status_type)
    where users.id = t.id;
    

    There are other techniques to achieve the same or similar effect, for example CASE expressions.

    EDIT

    As desired, a version with CASE instead of coalesce:

    update users
    set reference   = case when t.reference is not null
                           then t.reference else users.reference
                      end,
        status_type = case when t.status_type is not null
                           then t.status_type else users.status_type
                      end
    from (values (1, null, 11), (2, 12, null)) t(id,reference,status_type)
    where users.id = t.id;
    

    It is longer, but to make it shorter, you can omit the not and flip the contents of then ... else ..., but the version with coalesce is very compact.

    As suggested by JohnH in the comments, you can suppress unnecessary updates by adding a where clause:

    update users
    set reference   = case when t.reference is not null
                           then t.reference else users.reference
                      end,
        status_type = case when t.status_type is not null
                           then t.status_type else users.status_type
                      end
    from (values (1, null, 111), (2, 122, null)) t(id,reference,status_type)
    where users.id = t.id
      and (   (t.reference   IS NOT NULL and t.reference   IS DISTINCT FROM users.reference)
           or (t.status_type IS NOT NULL and t.status_type IS DISTINCT FROM users.status_type));