【问题标题】:Compare two database table and show changed column names比较两个数据库表并显示更改的列名
【发布时间】:2019-09-12 16:18:44
【问题描述】:

我有两个表,tmp1 和 tmp2:

tmp1:

+----+------+---------+---------+
| id | name | add1    | add2    |
+----+------+---------+---------+
| 1  | NULL | NULL    | NULL    |
| 2  | mum  | rajpur  | rajpur1 |
| 3  | mum1 | rajpur1 | rajpur2 |
| 4  | mum3 | rajpur3 | rajpur4 |
| 5  | mum4 | rajpur4 | rajpur5 |
+----+------+---------+---------+

tmp2:

+----+------+---------+---------+
| id | name | add1    | add2    |
+----+------+---------+---------+
| 1  | NULL | NULL    | NULL    |
| 2  | mum  | rajpur  | rajpur1 |
| 3  | mum1 | rajpur6 | rajpur7 |
| 4  | mum3 | rajpur3 | rajpur8 |
| 5  | mum4 | rajpur4 | rajpur5 |
+----+------+---------+---------+

在这里,我应用了一个 sql 查询,但是,空值属性的 id 或不匹配值属性的 id 将从第一个表中检索,并与第二个表进行比较:

SELECT a.id
FROM   tmp1 a
       INNER JOIN tmp2 b
               ON a.id = b.id
                  AND ( ( a.name IS NULL
                           OR a.add1 IS NULL
                           OR a.add2 IS NULL )
                         OR ( a.name != b.name
                               OR a.add1 != b.add1
                               OR a.add2 != b.add2 ) ); 

上面的 sql 查询给了我以下结果:

+----+
| id |
+----+
| 1  |
| 3  |
| 4  |
+----+

这很好,我使用上面的查询得到了我想要的结果。

现在我想检索第一个表中出现更改的那些列的名称,并与第二个表进行比较,或者在第一个表中保存列名的空值,我希望我的结果如下所示:

+----+-----------------+
| id | Changed Columns |
+----+-----------------+
| 1  | name,add1,add2  |
| 3  | add1,add2       |
| 4  | add2            |
+----+-----------------+

【问题讨论】:

  • “当你只有一把锤子时,一切看起来都像钉子。” ;)

标签: mysql


【解决方案1】:

您可以将Concat_ws() 函数与使用CASE .. WHEN 的条件检查一起使用。 Concat_Ws 函数的好处是,如果参数列表中有 NULL 值,它会忽略它(而不是连接它)。

因此,我们可以使用CASE .. WHEN 语句单独检查列,如果它们符合我们的条件,则返回列名(作为字符串),否则返回null

SELECT 
  a.id, 
  CONCAT_WS(',', 
            CASE WHEN a.name IS NULL OR a.name <> b.name THEN 'name' ELSE NULL END,
            CASE WHEN a.add1 IS NULL OR a.add1 <> b.add1 THEN 'add1' ELSE NULL END, 
            CASE WHEN a.add2 IS NULL OR a.add2 <> b.add2 THEN 'add2' ELSE NULL END
           ) AS Changed_Columns
FROM   tmp1 a
       INNER JOIN tmp2 b
               ON a.id = b.id
                  AND ( ( a.name IS NULL
                           OR a.add1 IS NULL
                           OR a.add2 IS NULL )
                         OR ( a.name <> b.name
                               OR a.add1 <> b.add1
                               OR a.add2 <> b.add2 ) );

结果

| id  | Changed_Columns |
| --- | --------------- |
| 1   | name,add1,add2  |
| 3   | add1,add2       |
| 4   | add2            |

View on DB Fiddle

【讨论】:

    【解决方案2】:

    如果不相等,则连接列名,如下所示:

    select a.id,
      trim(trailing ',' from concat(
        case when a.name = b.name then '' else 'name,' end,
        case when a.add1 = b.add1 then '' else 'add1,' end,
        case when a.add2 = b.add2 then '' else 'add2' end
      )) `Changed Columns`
    from tmp1 a inner join tmp2 b 
    on a.id=b.id and (
      (a.name is NULL or a.add1 is NULL or a.add2 is NULL) 
      or 
      (a.name!=b.name or a.add1!=b.add1 or a.add2!=b.add2)
    );
    

    请参阅demo
    结果:

    | id  | Changed Columns |
    | --- | --------------- |
    | 1   | name,add1,add2  |
    | 3   | add1,add2       |
    | 4   | add2            |
    

    【讨论】:

    • 似乎当列从非 NULL 值更改为 NULL 时,ON 子句会错过更改报告,例如考虑a.name = 'foo' AND b.name IS NULL ON 子句的最后一行可以更改为or NOT (a.name &lt;=&gt; b.name AND a.add1 &lt;=&gt; b.add1 AND a.add2 &lt;=&gt; b.add2 )
    • @spencer7593 什么 WHERE 子句?
    • ON 子句中的条件是 OP 的工作代码。我没有改变它。
    • 我只是指出“工作代码”在某些情况下不起作用;真的取决于对规范的解释。如果没有更精确的要求,我认为从非 NULL 值更改为 NULL 值将被视为更改。
    • 您应该将其指向 OP,尽管我认为您提到的案例已在此处介绍:a.name is NULL or a.add1 is NULL or a.add2 is NULL
    【解决方案3】:

    另一种方法:

    select id, group_concat(f order by f) as `Changed Columns` from (
        select tmp1.id, 'name' as f from tmp1 join tmp2 on tmp1.id = tmp2.id and (tmp1.name is null or tmp1.name <> tmp2.name)
        union
        select tmp1.id, 'add1' as f from tmp1 join tmp2 on tmp1.id = tmp2.id and (tmp1.add1 is null or tmp1.add1 <> tmp2.add1)
        union
        select tmp1.id, 'add2' as f from tmp1 join tmp2 on tmp1.id = tmp2.id and (tmp1.add2 is null or tmp1.add2 <> tmp2.add2)
    ) sq
    group by id
    order by id
    ;
    

    See DB Fiddle

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2013-12-04
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2021-09-14
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多