比较两列并用空值替换重复项

A.R*_*A.R 1 mysql mysql-5.6

我有一张这样的表:

id  | t1 | t2
---------------
 1  |  a |  b
 2  |  c |  a
 3  |  a |  e
 4  |  f |  g
 5  |  c |  c
Run Code Online (Sandbox Code Playgroud)

我想比较列t1t2相互比较以删除匹配值并在每列中获取唯一值,如下所示:

   t1 | t2
  -----------
    a |  b
    c |  null
 null |  e 
    f |  g
  null| null
Run Code Online (Sandbox Code Playgroud)

选择哪一行显示值以及其他哪一行显示空值并不重要。例如,由于a在原始数据集的第 3 行中也找到了值,因此以下输出也将有效:

   t1 | t2
  -----------
 null |  b
    c |  null
    a |  e 
    f |  g
  null| null
Run Code Online (Sandbox Code Playgroud)

最终目标是在两列中显示所有不同的值并且没有相同的值。

ype*_*eᵀᴹ 6

如果没有窗口函数,这在 MySQL 中非常困难。由于两列 -t1t2- 存储相似的内容,并且您只需要两列不同的值,因此在单个列中获取值会容易得多:

select t1 as tx from t
union distinct
select t2 from t ;
Run Code Online (Sandbox Code Playgroud)

我看不出有任何理由获得原始的复杂结果,除非您想保留表中其他列的信息并只从这 2 列中删除重复项。在这种情况下, anUPDATE会更有意义。

无论如何,这是一种获得此结果的方法。它假设(id)有一个UNIQUE约束。在dbfiddle.uk测试:

select t.id, gt1.tx as t1, gt2.tx as t2
from t
  left join
  ( select ut.tx, min(ut.id) as id
    from
      ( select id, t1 as tx from t
        union all
        select id, t2 from t
      ) ut 
    group by ut.tx
  ) as gt1
  on t.t1 = gt1.tx and t.id = gt1.id
  left join
  ( select ut.tx, min(ut.id) as id
    from
      ( select id, t1 as tx from t
        union all
        select id, t2 from t
      ) ut 
    group by ut.tx
  ) as gt2
  on t.t2 = gt2.tx and t.id = gt2.id and gt1.tx <> gt2.tx
 ;
Run Code Online (Sandbox Code Playgroud)

请注意,在具有 CTE 的 MariaDB(MySQL 的第一个表兄弟)中,可以更紧凑、更清晰地重写相同的查询:

with gt as 
  ( select ut.tx, min(ut.id) as id
    from
      ( select id, t1 as tx from t
        union all
        select id, t2 from t
      ) ut 
    group by ut.tx
  ) 
select t.id, gt1.tx as t1, gt2.tx as t2
from t
  left join gt as gt1
    on t.t1 = gt1.tx and t.id = gt1.id
  left join gt as gt2
    on t.t2 = gt2.tx and t.id = gt2.id and gt1.tx <> gt2.tx
 ;
Run Code Online (Sandbox Code Playgroud)

不过,从逻辑上讲,这两种变体的工作方式相同。这个子选择:

  ( select ut.tx, min(ut.id) as id
    from
      ( select id, t1 as tx from t
        union all
        select id, t2 from t
      ) ut 
    group by ut.tx
  ) 
Run Code Online (Sandbox Code Playgroud)

返回所有不同t1t2与第一的ID一起值1行,其中每个遇到。对于您的示例,它会产生以下输出:

tx   id
---  ---
a    1
b    1
c    2
e    3
f    4
g    4
Run Code Online (Sandbox Code Playgroud)

上面的集合与原始表连接了两次, ont1和 on t2。在每种情况下,如果原始行的 ID 与子选择行的 ID 匹配,则该值将原封不动地返回,因为匹配表明该行是该值的第一次出现;否则该值将被替换为空值。


1 ID 顺序为“第一个”。